As projects usually tend to spread across many months of development, creating new projects is not something we as developers do often.
So I put together this little “cheat sheet” as a reminder. It contains some most common commands and settings for starting a new Django project aimed at building a RESTful API with Django REST Framework.
Install dependencies
Install Django + DRF with pip:
pip install -U django djangorestframework django-filter drf-yasg
Install Django + DRF with Anaconda
If you prefer more than one snake in your life 😉:
conda install -c conda-forge django djangorestframework django-filter drf-yasg
NOTE: The commands above includedrf-yasg
for auto-generated Swagger documentation anddjango-filter
for filtering on endpoints. Feel free to skip those if not needed.
Start a new Django project
django-admin startproject myproject .
The dot .
at the end indicates that the project files will be created in the folder you’re currently in rather than a new folder.
If you get an error message saying No module named django-admin
the following command should help:
python -m django startproject myproject .
Configure database access
PostgreSQL
For connecting to PostgreSQL, you’ll need to install the following package:
pip
pip install -U psycopg2-binary
Anaconda
conda install -c conda-forge psycopg2-binary
Then update the DATABASES
object in the settings.py
file of your project:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
... # NAME, USER, PASSWORD, HOST are here
'PORT': '5432',
}
}
For more info, such as how to install and configure PostgreSQL on your local machine, check out this article about running a DRF API with PostgreSQL.
MySQL
MySQL connections require the following dependency:
pip
pip install -U mysqlclient
Anaconda
conda install -c conda-forge mysqlclient
Then update the DATABASES
object in the settings.py
file of your project:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
... # NAME, USER, PASSWORD, HOST are here
'PORT': '3306',
}
}
For more info, such as how to install and configure MySQL on your local machine, check out this article about running a DRF API with MySQL.
MongoDB
MongoDB is not natively supported by Django. There is a good third-party database engine called Djongo, but it’s still in development.
I wrote an article about building a Django app with DRF and MongoDB and what alternatives you have – feel free to check it out for more details.
To install Djongo run the following:
pip
pip install -U djongo pymongo[srv]
Anaconda
conda install -c conda-forge djongo pymongo dnspython
Then update the DATABASES
object in the settings.py
file of your project:
DATABASES = {
'default':
{
'ENGINE': 'djongo',
'NAME': '<database-name>',
'CLIENT':
{
# Access details are put together as one string
'host':
'mongodb+srv://<mongodb-user>:<password>'
'@<mongodb-host>/<database-name>'
'?retryWrites=true&w=majority'
}
}
}
Create local apps
Here is how to spin up a new local app:
python manage.py startapp myapp
Add DRF and local apps to Installed Apps
Add DRF (and optionally drf-yasg
) to the Installed Apps inside your settings.py
file. If any of your local apps will have database migrations, don’t forget to include them as well.
INSTALLED_APPS = [
...
'rest_framework',
# 'rest_framework.authtoken' # For token auth
# 'drf_yasg', # For Swagger
'myapp.apps.Config', # Your local app config
]
Something I found quite neat is separating Installed Apps into three separate lists:
- Django apps
- Third party packages
- Local apps
Here’s a snippet if you want to do that:
DJANGO_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
THIRD_PARTY_APPS = [
'rest_framework',
# 'rest_framework.authtoken' # For token auth
# 'drf_yasg', # For Swagger
]
LOCAL_APPS = [
'myapp.apps.Config', # Your local app config
]
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
Configure DRF settings
Here is the complete snippet I use as a DRF settings kick-starter. There are also more details for each section further in the article.
REST_FRAMEWORK = {
# Rendering
# https://www.django-rest-framework.org/api-guide/renderers/
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
# Authentication
# https://www.django-rest-framework.org/api-guide/authentication/
'DEFAULT_AUTHENTICATION_CLASSES': [
# Choose whichever auth you're going to use
# 'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.TokenAuthentication',
# 'rest_framework.authentication.RemoteUserAuthentication',
],
# Permissions
# https://www.django-rest-framework.org/api-guide/permissions/
'DEFAULT_PERMISSION_CLASSES': [
# Choose whichever permissions you're going to use
# 'rest_framework.permissions.IsAuthenticated',
# 'rest_framework.permissions.IsAuthenticatedOrReadOnly',
# 'rest_framework.permissions.IsAdminUser',
# 'rest_framework.permissions.AllowAny',
],
# Parsers
# https://www.django-rest-framework.org/api-guide/parsers/
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
],
# Filtering
# https://www.django-rest-framework.org/api-guide/filtering/
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
],
# Pagination
# https://www.django-rest-framework.org/api-guide/pagination/
'DEFAULT_PAGINATION_CLASS': None,
# Pagination options:
# 'rest_framework.pagination.PageNumberPagination'
# 'rest_framework.pagination.LimitOffsetPagination'
# 'rest_framework.pagination.CursorPagination'
'PAGE_SIZE': 20,
}
if DEBUG:
# Rendering
REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'].append(
'rest_framework.renderers.BrowsableAPIRenderer',
)
# Authentication
REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'].append(
'rest_framework.authentication.SessionAuthentication',
)
Default Renderer Classes
Django REST Framework uses the following classes as default API renderers:
rest_framework.renderers.JSONRenderer
andrest_framework.renderers.BrowsableAPIRenderer
But you might want to disable Browsable API in production since it has some security concerns. Here is a snippet to only use it when DEBUG
mode is on:
REST_FRAMEWORK = {
...
# Rendering
# https://www.django-rest-framework.org/api-guide/renderers/
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
...
}
if DEBUG:
# Rendering
REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'].append(
'rest_framework.renderers.BrowsableAPIRenderer',
)
Default authentication classes
By default, DRF uses the following classes for authentication:
rest_framework.authentication.SessionAuthentication
rest_framework.authentication.BasicAuthentication
But the session auth implies the use of cookies which is not entirely stateless. In production, you’re likely to use some token-based authentication.
Similarly, we can use the session auth only when DEBUG
is on since it works well with the Browsable API:
REST_FRAMEWORK = {
...
# Authentication
# https://www.django-rest-framework.org/api-guide/authentication/
'DEFAULT_AUTHENTICATION_CLASSES': [
# Choose any auth to use in production
# 'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.TokenAuthentication',
# 'rest_framework.authentication.RemoteUserAuthentication',
],
...
}
if DEBUG:
# Authentication
REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'].append(
'rest_framework.authentication.SessionAuthentication',
)
Default permission classes
By default, DRF uses rest_framework.permissions.AllowAny
class that exposes all API endpoints to the public without any authentication. In most cases, this isn’t what we want.
Here is a snippet to reconfigure it:
REST_FRAMEWORK = {
...
# Permissions
# https://www.django-rest-framework.org/api-guide/permissions/
'DEFAULT_PERMISSION_CLASSES': [
# Choose whichever permissions you're going to use
# 'rest_framework.permissions.IsAuthenticated',
# 'rest_framework.permissions.IsAuthenticatedOrReadOnly',
# 'rest_framework.permissions.IsAdminUser',
# 'rest_framework.permissions.AllowAny',
],
...
}
Default parser classes
Django REST Framework uses the three following classes to parse submitted data by default:
rest_framework.parsers.JSONParser
rest_framework.parsers.FormParser
rest_framework.parsers.MultiPartParser
There is no harm in it, but you might want to reconfigure your API to only accept one data format by default and handle other formats on a view level:
REST_FRAMEWORK = {
...
# Parsers
# https://www.django-rest-framework.org/api-guide/parsers/
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
],
...
}
Default filter Backends
DRF doesn’t provide any filtering on endpoints by default, but it’s often desired functionality.
If you haven’t installed django-filter
yet, refer to the installation section above for the snippet to install it.
Then configure the filters in DRF settings:
REST_FRAMEWORK = {
...
# Filtering
# https://www.django-rest-framework.org/api-guide/filtering/
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
],
...
}
Default pagination class and page size
Since you’ll most likely need pagination in your API at some point, it might be a good idea to configure it straight away:
REST_FRAMEWORK = {
...
# Pagination
# https://www.django-rest-framework.org/api-guide/pagination/
'DEFAULT_PAGINATION_CLASS': None,
# Pagination options:
# 'rest_framework.pagination.PageNumberPagination'
# 'rest_framework.pagination.LimitOffsetPagination'
# 'rest_framework.pagination.CursorPagination'
'PAGE_SIZE': 20,
...
}
Configure URLs
Configure Browsable API
If you’re going to use Browsable API, don’t forget to add its login and logout views to the urls.py
file of your project:
...
from django.urls import path, include
urlpatterns = [
...
# Browsable API views
path('api-auth/', include('rest_framework.urls')),
]
Add Swagger endpoints
To configure Swagger, add the following snippet to the urls.py
file (and adjust the parameters):
...
from django.urls import path, re_path, include
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
# Init Swagger schema view
SchemaView = get_schema_view(
openapi.Info(
title='Your API name',
default_version='v1',
description='Your API description',
terms_of_service='your terms of service url',
contact=openapi.Contact(email='your contact email'),
license=openapi.License(name='BSD License'),
),
public=True,
permission_classes=(permissions.AllowAny,),
)
urlpatterns = [
# Swagger views
re_path(
r'^swagger(?P<format>\.json|\.yaml)$',
SchemaView.without_ui(cache_timeout=0),
name='schema-json'
),
path(
'swagger/',
SchemaView.with_ui('swagger', cache_timeout=0),
name='schema-swagger-ui'
),
path(
'redoc/',
SchemaView.with_ui('redoc', cache_timeout=0),
name='schema-redoc'
),
... # The rest of urlpatterns
]
This will add the following four endpoints:
- A JSON view of your API specification at
/swagger.json
- A YAML view of your API specification at
/swagger.yaml
- A swagger-ui view of your API specification at
/swagger/
- A ReDoc view of your API specification at
/redoc/
Why create this cheat sheet?
You might be wondering – why create this cheat sheet when each of those plugins already has excellent documentation?
It’s simple – to save you and me time looking things up across various online resources by assembling the most common commands and settings together.
The intention is to make this cheat sheet a handy resource for everyone and share good practices within the community.
So if you have something to contribute, leave a comment below!