How To Build Scalable Systems with Django Framework

woman working app development django
Summary
  • The Django Starter Kit is a dockerized, production-ready project containing reusable modules (like authentication, user management, and terms of agreement), pre-configured packages, and a styleguide to accelerate project setup.
  • The architecture is divided into a core app, which holds shared settings, abstractions, and utilities, and other independent apps that follow a standardized structure with views, use cases, docs, tests, and serializers per endpoint.
  • App independence and code reusability are maintained by extracting common code to the core app, using Django's Proxy Model to extend core models, and using unmanaged models to avoid unnecessary dependencies between apps.
  • Planned future improvements include adding more modules such as push notifications and evaluating Django Ninja as a potential replacement for Django REST Framework to reduce boilerplate code.

At Cheesecake Labs, we work on a wide range of projects, each with unique demands and complexities. After 10 years of working with clients to build scalable digital products that help solve real-world problems, we’ve noticed some recurring themes in our work.

  • Duplicated work: Despite each project being unique, certain elements of everything we work on are boilerplate, and we repeat similar tasks from one project to the next. We could accelerate our initial deliveries and reduce project timelines with standardized setups.
  • Architectural variance: Each project had a distinct architecture and development style. Creating a base architecture and a styleguide would make it easier for developers to transition between projects.

With these challenges in mind, we decided to put together starter kits on our main stack that we can use from one project to the next. 

Let’s take a look at the details of our Django Starter Kit.

In this post: 

What is the Django Starter Kit?

The Django Starter Kit is a project in constant revision. It’s designed to contain reusable code for most of our projects in a robust and scalable architecture, ensuring each project starts out with a strong and adaptable foundation.

Our starter is more than just boilerplate code. It’s a dockerized, production-ready project containing:

  • Modules: Logic required for any project, including authentication, user management, and terms of agreement. Each module is designed to be easy to extract or extend.
  • Pre-configured packages: The best settings for Django, Django Rest framework, incorporating error monitoring, interactive API documentation, and other valuable components.
  • Styleguide: Comprehensive documentation offering detailed architectural insights, best practices, and conventions. We developed our own styleguide based on an existing styleguide.

The architecture

Our architecture is composed of two types of modules — the core app and other apps. The main goal is to ensure that all apps, besides the core app, remain independent and decoupled.

The core app

The core app serves as the backbone of our project, containing essential components that are required across the entire application. It contains various functionalities, including settings, common code, abstractions, and utilities that can be shared and used by other apps within the project.

Other Apps

All other apps are modules that can interact with the core app. They all share a similar structure that looks like this:

.
├── models
│ └── ...
├── services
│ └── ...
├── utils
│ └── ...
├── v1
│ ├── user
│ │ ├── get
│ │ │ ├── views.py
│ │ │ ├── docs.py
│ │ │ ├── serializers.py
│ │ │ ├── tests_get_user.py
│ │ │ ├── use_case.py
│ │ │ └── ...
│ │ ├── ...
│ ├── urls.py
│ └── ...
├── urls.py
├── conftest.py
└── ...Code language: Django (django)

Some files like __init__.py and migrations were omitted to keep only the most important aspects of the structure.

In our architecture, every endpoint has a folder containing the following:

  • View: Each API should contain one view. The view handles the incoming requests and returns the appropriate responses.
  • Use cases: Each API should have one use case, which should be called by the view. Use cases represent the business logic of the API.
  • Docs: Each API should have documentation specifications. The Documentation file contains the API definition and is used to generate the OpenAPI page.
  • Tests: Comprehensive test suites should be created for each API to cover various scenarios, including edge cases and error conditions.
  • Request and response serializers: Each API should have request and response serializers. Serializers help with data validation and transformation.

In scenarios where multiple use cases share similar business logic, business logic is extracted and consolidated into the services or the utils folder, ensuring a cohesive and organized codebase. Our architectural philosophy emphasizes keeping business logic within specific designated areas: use cases, models, and services/utils. 

App independence and code reusability

Keeping code readable and maintainable can be a big challenge. That’s why keeping the apps decoupled is so important. 

This is how we handle app independence in the starter kit:

  • To promote code reusability, we extract code snippets that are common across multiple apps to the core app. Of course, some code redundancy is acceptable.
  • When we need to extend a highly specific property from the core model, we use Django’s Proxy Model. This allows us to extend the core model’s functionality without altering its core behavior. Here’s an example:
from core.models import User as CoreUser

class User(CoreUser):
    def my_app_specific_property(self):
        ...

    class Meta:
        proxy = TrueCode language: Django (django)
  • When creating a relationship with a model that does not belong to its app or the core, we opt for unmanaged models. This approach lets us use the model without importing the original and avoids unnecessary dependencies.
class ModelName(BaseModel):
    essential_field = models.TextField()

    class Meta:
        managed = False
        db_table = 'original_app_model_name'

class ModelWhichNeedsRelationship(BaseModel):
    relation = models.ForeignKey(ModelName, ...)
    ...Code language: Django (django)

Future improvements

The Django starter kit has been essential in maintaining code quality and consistency across our projects. 

But our journey doesn’t end here. At Cheesecake Labs, we recognize that web and mobile development requires ongoing adaptation and innovation.

We firmly believe that while our current approach is a robust foundation, there’s no silver bullet. We remain committed to refining our architecture to meet the unique demands of each project that comes our way.

Some of the exciting features we’re planning for the future:

  • More modules: We’ve mapped more frequently used modules that should be integrated into our starter to improve our delivery time. For example, we plan to add a push notification module.
  • Framework alternatives: We are considering whether Django Ninja is a better alternative than Django REST Framework for our starter kit. This replacement could significantly reduce boilerplate code because simple typehints would replace the serializers and API specifications.

We’re excited to keep innovating and finding new ways to streamline our development and build better products for our clients. 

Learn more about how we work 

To learn more about how we work at Cheesecake Labs, check out the rest of our blog, where we cover all things software development and design and dive deep into our processes and approach.

And if you’d like expert help building delightful digital products, let’s chat! We’d love to hear from you.

build scalable applications

Explore our blog for more Django Framework content:

FAQ

What is the Django Starter Kit?

The Django Starter Kit is a project in constant revision designed to contain reusable code for most projects in a robust and scalable architecture. It's a dockerized, production-ready project that includes modules (such as authentication, user management, and terms of agreement), pre-configured packages (with settings for Django, Django Rest Framework, error monitoring, and interactive API documentation), and a comprehensive styleguide with architectural insights, best practices, and conventions.

What problems does the Django Starter Kit aim to solve?

It addresses two recurring challenges: duplicated work, where boilerplate elements were repeated across projects, and architectural variance, where each project had a distinct architecture and development style. Standardized setups accelerate initial deliveries, reduce project timelines, and make it easier for developers to transition between projects.

How is the architecture structured?

The architecture is composed of two types of modules: the core app and other apps. The core app serves as the backbone, containing essential components like settings, common code, abstractions, and utilities shared across the project. Other apps are modules that interact with the core app while remaining independent and decoupled. Each app contains folders for models, services, utils, and versioned endpoints (e.g., v1), where every endpoint has its own view, use case, docs, tests, and request/response serializers.

How does the starter kit handle app independence and code reusability?

Code snippets common across multiple apps are extracted to the core app. When extending a specific property from a core model, Django's Proxy Model is used to add functionality without altering core behavior. When creating relationships with models outside an app or the core, unmanaged models are used to avoid unnecessary dependencies. Business logic is kept within designated areas: use cases, models, and services/utils.

What future improvements are planned for the Django Starter Kit?

Planned improvements include adding more modules (such as a push notification module) to improve delivery time, and evaluating Django Ninja as a potential alternative to Django REST Framework, which could significantly reduce boilerplate code by replacing serializers and API specifications with simple typehints.

About the author.

Karran Besen
Karran Besen

A computer scientist who loves to study new technologies. Also enjoys rap, watching movies and TV shows, sports (especially soccer), and playing videogames.