How to structure the Django Project?
A Comprehensive Guide to Organizing and Scaling the Django Project
Django's Command Line Interface (CLI) is a powerful tool for generating well-structured Django projects. However, maintaining that clean structure can become challenging as we create multiple apps, models, views, and routes. In this article, we'll unveil our preferred method for organizing Django projects. This approach has proven invaluable in creating and sustaining an organized and understandable directory structure, even as our Django project evolves and scales.
The Default Structure
project/
|-- app/
| |-- migrations/
| | |-- __init__.py
| |-- __init__.py
| |-- admin.py
| |-- apps.py
| |-- models.py
| |-- tests.py
| |-- views.py
|-- project/
| |-- __init__.py
| |-- settings.py
| |-- urls.py
| |-- asgi.py
| |-- wsgi.py
|-- manage.py
|-- requirements.txt
When we create an app in Django, a folder is made with the name of the app, and typically, it consists of a migrations
folder and several files to configure the admin, models, tests, and views.
While it is an excellent structure already, the problem arises when the project grows. One of my projects had almost 80+ models. So, we can’t have a single Python file with thousands of lines. I mean, we can, but then it becomes a lot less readable.
So then, how do we do it? Making sure we have scope to grow it to a certain point where it is still easier to expand without affecting the readability of it.
The Solution
Strategy 1: Organizing Models and Views
Over time, the original problem revolved around the increasing size of our Django project's models and view files. Django doesn't strictly enforce placing all models inside the models.py
file.
Instead, it offers the flexibility to structure our project how we see fit. We've devised a simple yet effective solution to address this issue: organizing models and views by placing them in separate files within dedicated directories. The updated project structure would resemble the following:
project/
|-- app/
| |-- migrations/
| | |-- __init__.py
| |-- __init__.py
| |-- admin.py
| |-- apps.py
| |-- models/
| | |-- __init__.py
| | |-- model1.py
| | |-- model2.py
| | |-- ...
| |-- views/
| | |-- __init__.py
| | |-- view1.py
| | |-- view2.py
| | |-- ...
| |-- tests.py
|-- project/
| |-- __init__.py
| |-- settings.py
| |-- urls.py
| |-- asgi.py
| |-- wsgi.py
|-- manage.py
|-- requirements.txt
By adopting this approach, we maintain a clean and modular project structure, ensuring that our models and views remain organized and readable as our project grows.
models Directory
The presence of an __init__.py
file in the models’ directory serves several important purposes:
Namespace Organization
By declaring the models’ directory as a package with __init__.py
, we establish an explicit namespace for our models. This allows us to organize and structure our models into multiple files while maintaining them within the same logical package. This becomes increasingly beneficial as our project grows and we introduce numerous models.
Import Convenience
The __init__.py
file allows us to easily import our models from other parts of our app or project. For instance, we can import a model like this:
from app.models import MyModel
views Directory
Similarly, in the views directory, the __init__.py
file plays a vital role:
Namespace Organization
It aids in organizing our views into separate files within the views package. Each view file can focus on specific views or functionality, enhancing the overall code maintainability.
Import Convenience
With the __init__.py
file in place; we can effortlessly import our view functions or classes from the views directory into other parts of our code. This includes usage in our URL routing (urls.py
) or different views.
By including these __init__.py
files, we improve our Django project's organization, structure, and maintainability, making it easier to manage as it continues to evolve and expand.
Strategy 2: Taking It a Step Further
While Strategy 1 addresses our problem effectively, we can refine it further to enhance our project's structure and maintainability.
But before we delve into these improvements, let's take a moment to discuss the concept of apps in Django.
Creating Apps in Django
Before we proceed, it's essential to understand the technical definition of an app within a Django project, as per the official documentation1:
Applications include some combination of models, views, templates, template tags, static files, URLs, middleware, etc. They’re generally wired into projects with the
INSTALLED_APPS
setting and optionally with other mechanisms such as URLconfs, theMIDDLEWARE
setting, or template inheritance.
Dividing Apps Based on Business Functions
When structuring my Django projects, dividing them based on the core business functions they serve is crucial. This approach enhances project organization and makes managing and maintaining over time easier.
For instance, let's take the example of a Content Management System (CMS) I built in Django. Here's how I typically divide it into multiple apps:
CMS App: I create models and views for the fundamental shared resources that define the CMS in this app. This includes entities like categories, tags, posts, and more.
IAM (Identity and Access Management) App: To handle user authentication, extend user models, and manage roles and permissions, I create a dedicated IAM app. This keeps authentication-related code separate and well-organized.
Notification App: For managing various types of notifications, whether they are in-app notifications, emails, browser notifications, or others, I established a distinct notification app. This centralized approach ensures efficient notification handling throughout the project.
By structuring the project this way, instead of randomly creating apps for every model, we align each app with a specific business function. This promotes clarity and maintainability and streamlines the development process, making it easier to scale and expand the project as business requirements evolve.
This strategy enhances the organization of the Django project and aligns development efforts with the underlying business objectives, ensuring a more cohesive and efficient project structure.
Creating Resources in the Django App
Let's delve deeper into what constitutes a resource in my context of a Django app:
What is a Resource?
I define a resource as a cohesive collection of components that work together to fulfil a specific functionality. These components typically include Models, Views or ViewSets, related Tests, and Serializers. I further split the app into resources to maintain an organised codebase, each representing a distinct functional unit.
Resource Structure
The project structure I typically follow looks like the following:
project/
|-- app/
| |-- resource1/
| | |-- models.py
| | |-- views.py
| | |-- admins.py
| | |-- serializers.py
| | |-- filters.py
| | |-- tests/
| | | |-- test_1.py
| | | |-- test_2.py
| | | |-- ...
| |-- resource2/
| | |-- models.py
| | |-- views.py
| | |-- admins.py
| | |-- serializers.py
| | |-- filters.py
| | |-- tests/
| | | |-- test_1.py
| | | |-- test_2.py
| | | |-- ...
| |-- migrations/
| | |-- __init__.py
| | |-- ...
| |-- urls.py
|-- project/
| |-- __init__.py
| |-- settings.py
| |-- urls.py
| |-- asgi.py
| |-- wsgi.py
|-- manage.py
|-- requirements.txt
Model as a Resource
Regarding whether the name of a model can be considered a resource, it depends. A resource typically encompasses similar models that are closely related. If the models within the models.py
file of a resource directory are closely related and serve a common purpose, then naming the resource after the primary model makes sense. However, if the models are not closely related, keeping them in separate resource directories is advisable.
This project structure has proven effective for me over time, but it's essential to remember that project organization can vary based on individual preferences and project requirements. Feel free to adapt and modify it to suit your needs and preferences.
Conclusion
In conclusion, the structure and organization of a Django project play a pivotal role in its maintainability and scalability. Throughout this discussion, we've explored strategies and best practices for creating a well-structured Django project and how to divide it into smaller, manageable units called resources.
By dividing our project into resources based on business functions, we achieve clarity and maintainability, making it easier to navigate and extend as our project evolves. Each resource encapsulates related models, views, tests, serializers, and filters, creating a modular and organized codebase.
It's important to note that while the project structure outlined here has proven effective, it's not a one-size-fits-all solution. Adaptations can be made to align with specific project requirements and personal preferences.
Ultimately, a well-organized Django project, with clear resource boundaries and thoughtful structuring, contributes significantly to project success. It promotes maintainability, teamwork, and adaptability, ensuring your Django application remains robust and adaptable as it grows and evolves.
https://docs.djangoproject.com/en/4.2/ref/applications/