SQLAlchemy: Designing a Shortened URL Service Database

Updated: January 3, 2024 By: Guest Contributor Post a comment

Introduction

In today’s digital landscape, the creation of shorter, more manageable URLs is essential. This tutorial will guide you through using SQLAlchemy to design a database for a shortened URL service, following a step-by-step approach.

Getting Started with SQLAlchemy

SQLAlchemy is a Python SQL toolkit and Object-Relational Mapping (ORM) library that provides a full suite of well-known enterprise-level persistence patterns. First, ensure you have SQLAlchemy installed:

pip install SQLAlchemy

Now, let’s start by setting up a basic model for our URL shortening service:

from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from datetime import datetime

Base = declarative_base()

class ShortenedUrl(Base):
    __tablename__ = 'shortened_urls'
    id = Column(Integer, primary_key=True)
    original_url = Column(String, nullable=False)
    short_code = Column(String(10), unique=True, nullable=False)
    created_at = Column(DateTime, default=datetime.utcnow)

# Create the engine linked to a SQLite database 'shorturl.db'.
engine = create_engine('sqlite:///shorturl.db')

# Create all tables in the engine. This is equivalent to 'Create Table' in raw SQL.
Base.metadata.create_all(engine)

Creating and Managing Sessions

To interact with our database, we need to create a session:

Session = sessionmaker(bind=engine)
session = Session()

With this session, you can now add, delete, and query objects in your database.

Adding New URLs

Let’s define a function to add a new URL with a unique shortened code to our database:

def add_url(original_url, short_code):
    new_url = ShortenedUrl(original_url=original_url, short_code=short_code)
    session.add(new_url)
    session.commit()

Now, you can call add_url() with the original URL and a short code that uniquely identifies the particular URL.

Retrieving and Redirecting URLs

The next step is to retrieve the original URL from the short code:

def get_original_url(short_code):
    return session.query(ShortenedUrl)
                  .filter(ShortenedUrl.short_code == short_code)
                  .first()

This function will enable us to redirect users to the original URLs when the shortened URL is accessed.

Advanced Features

Besides basic URL addition and retrieval, a pragmatic short URL service may need advanced features like URL hit tracking, deletion after a set expiration time, and more.

Tracking Hits

class UrlHit(Base):
    __tablename__ = 'url_hits'
    id = Column(Integer, primary_key=True)
    short_url_id = Column(Integer, ForeignKey('shortened_urls.id'))
    accessed_at = Column(DateTime, default=datetime.utcnow)

Base.metadata.create_all(engine) # Repeat this if you've defined new models after the initial run.

Storing hits to a URL allows you to track the number of times a shortened URL is accessed over time. Use the following function to record a URL hit:

def log_url_hit(short_url_id):
    hit = UrlHit(short_url_id=short_url_id)
    session.add(hit)
    session.commit()

Expiration and Cleanup

To set up expiration for URLs, you can add an additional field to the ShortenedUrl model:

class ShortenedUrl(Base):
    # ...
    expires_at = Column(DateTime)

    # Add a method to check if the URL is expired
    def is_expired(self):
        return datetime.utcnow() > self.expires_at if self.expires_at else False

You can now write a scheduler that regularly checks for expired URLs and deletes them:

def delete_expired_urls():
    session.query(ShortenedUrl)
          .filter(ShortenedUrl.expires_at < datetime.utcnow())
          .delete(synchronize_session=False)
    session.commit()

Putting it All Together

With these components in place, you can now build a complete shortened URL service. Each piece can be expanded upon to include more functionality as required by your application needs.

Conclusion

SQLAlchemy is a flexible ORM that enables Python developers to produce database-interacting code efficiently and in an object-oriented manner. By following this tutorial, you’ve learned how to design a robust database for a URL shortening service using the latest SQLAlchemy practices.