These are some best practices to use when developing Django projects.
- Always subscribe to the idea of "Fat models, thin views, stupid templates, and utility modules."
- View and template logic should be as minimal as humanly possible.
- Logic that cannot be added as a Model or Manager method should be in a utility module (
utils.pyfile within an app)
- Logic that applies across apps should live in a project-wide
- For implementing APIs, use Django REST Framework; we have our own best practices for using DRF.
- Always import settings via the
python from django.conf import settings
- Always use a
models.Managersubclass if the logic is operating on a set of models.
- Prefer class methods of
models.Managersubclasses for overriding
__init__on a model.
models.Managersubclass helpers for operating on tables or collections, e.g.
- Prefer class methods of
- Define methods on your Model classes to handle logic that operates on a single object instance.
filter()for AND conditions in queries, and
Qobjects for OR conditions.
values_list()to avoid instantiation of a model whenever possible.
select_related()if traversing a related field to avoid additional queries for ForeignKey relations.
prefectch_related()to reduce the number of queries necessary for M2M relations.
- Django's QueryAPI documentation is your friend; read it as often as necessary.
Blank vs Null
Django's ORM maps models and querysets back to a relational database. Most fields can be defined with options to allow
NULL values (
null=True) or blank values (
blank=True). What's important to remember is that
null relates to the database itself, whereas
blank relates to field validation only. Typically,
NULL values indicate that a field on a model wasn't set to anything, and so there's no value to put in the corresponding database column. However, allowing TextFields or CharFields to be both null and blank leads to a situation where two values could represent the absence of data. For this reason, you should not use
null=True for these fields (or subclasses of these fields, such as EmailField).
The database does not care if a
CharField is blank or not, however. This is only taken into account when validating input when creating a model instance (or deserializing input from an API.) In almost all circumstances, you should generally set text-type fields to
blank=True if a field is allowed to have no value, and
default='' in order to fill the field when no input is specified.
- Always provide a name field for a route for easy reverse lookups
- End all your URL regex strings with
/?$; this makes the trailing slash optional
In general, we stick to the basic Django project layout. Your root repository folder will typically contain configuration files like the main
.drone.yml, etc, as well as the main project filter generated with the
startproject command. Inside the project folder is another folder of the same name, where
wsgi.py and the root
urls.py live, known as the configuration folder. The
manage.py command also lives here.
When you use the
startapp command, it will create a folder with
tests.py files inside. Try to limit each app to a specific feature, and only create those models needed to implement that feature.
Since we primarily use Django combined with Django REST Framework (DRF) to build RESTful API servers, some of the default Django applications and middleware are unecessary and add memory and performance overhead for unneeded features. It is therefore recommended to remove the following default apps and middleware from the
MIDDLEWARE_CLASSES settings, respectively:
# Unnecessary apps 'django.contrib.sessions' 'django.contrib.messages' 'django.contrib.staticfiles' # Unnecessary middleware 'django.contrib.sessions.middleware.SessionMiddleware' 'django.middleware.csrf.CsrfViewMiddleware' 'django.contrib.auth.middleware.SessionAuthenticationMiddleware' 'django.contrib.messages.middleware.MessageMiddleware'
Note: If you are using DRF's built-in browsable API feature, it relies on Django's session-based authentication to work. You'll need to leave in
INSTALLED_APPS as well as
Django REST Framework
For more specifics around building a Django-based API project, check our DRF best practices.