Sling Academy
Home/SQLAlchemy/SQLAlchemy: Designing a Shortened URL Service Database

SQLAlchemy: Designing a Shortened URL Service Database

Last updated: January 03, 2024

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.

Next Article: SQLAlchemy: Designing a Social Network Database Schema

Previous Article: SQLAlchemy: Data Migration in Production

Series: SQLAlchemy Tutorials: From Basic to Advanced

SQLAlchemy

You May Also Like

  • SQLAlchemy: Counting rows for each category (2 approaches)
  • SQLAlchemy: Adding a calculated column to SELECT query
  • SQLAlchemy: Grouping data on multiple columns
  • SQLAlchemy: How to temporarily delete a row
  • SQLAlchemy Composite Indexes: The Complete Guide
  • Full-Text Search in SQLAlchemy: The Ultimate Guide
  • SQLAlchemy: What if you don’t close database connections?
  • SQLAlchemy: How to Remove FOREIGN KEY Constraints (2 Ways)
  • SQLAlchemy: How to Create and Use Temporary Tables
  • SQLAlchemy: Saving Categories and Subcategories in the Same Table
  • SQLAlchemy: How to Automatically Delete Old Records
  • Weighted Random Selection in SQLAlchemy: An In-Depth Guide
  • SQLAlchemy: created_at and updated_at columns
  • How to Use Regular Expressions in SQLAlchemy
  • SQLAlchemy: Ways to Find Results by a Keyword
  • SQLAlchemy: How to Connect to MySQL Database
  • SQLAlchemy: How to Bulk Insert Data into a Table
  • SQLAlchemy: How to Update a Record by ID
  • SQLAlchemy: Singular vs Plural Table Names