Skip to the content.

Django Cheatsheet

Table Of Contents

Django-Admin Commands

Built-in Commands

Custom Commands

Add management/commands directory to the application. _ modules will be ignored.

polls/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            _private.py
            closepoll.py
    tests.py
    views.py

Add this sample class:

from django.core.management.base import BaseCommand, CommandError

class Command(BaseCommand):
    help = "Closes the specified poll for voting"

    def add_arguments(self, parser):
        # Positional arguments
        parser.add_argument("poll_ids", nargs="+", type=int)

        # Named (optional) arguments
        parser.add_argument(
            "--delete",
            action="store_true",
            help="Delete poll instead of closing it",
        )

    def handle(self, *args, **options):
        for poll_id in options["poll_ids"]:
            try:
                poll = Poll.objects.get(pk=poll_id)
            except Poll.DoesNotExist:
                raise CommandError('Poll "%s" does not exist' % poll_id)

            poll.opened = False
            poll.save()

            self.stdout.write(
                self.style.SUCCESS('Successfully closed poll "%s"' % poll_id)
            )

Middleware

Middlewares are like decorators.

def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.
        # Change request object. e.g. request.profile = Profile.objects.get(user=request.user.id)

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware

CSRF Protection

  1. The CSRF middleware is activated by default in the MIDDLEWARE setting. If you override that setting, remember that django.middleware.csrf.CsrfViewMiddleware should come before any view middleware that assume that CSRF attacks have been dealt with.

    If you disabled it, which is not recommended, you can use csrf_protect() on particular views you want to protect (see below).

  2. In any template that uses a POST form, use the csrf_token tag inside the <form> element if the form is for an internal URL, e.g.:
     <form method="post">{% csrf_token %}
    

    This should not be done for POST forms that target external URLs, since that would cause the CSRF token to be leaked, leading to a vulnerability.

  3. In the corresponding view functions, ensure that RequestContext is used to render the response so that {% csrf_token %} will work properly. If you’re using the render() function, generic views, or contrib apps, you are covered already since these all use RequestContext.

Setting the token on the AJAX request

const request = new Request(
    /* URL */,
    {
        method: 'POST',
        headers: {'X-CSRFToken': csrftoken},
        mode: 'same-origin' // Do not send CSRF token to another domain.
    }
);
fetch(request).then(function(response) {
    // ...
});

Dynamic Forms

If your view is not rendering a template containing the csrf_token template tag, Django might not set the CSRF token cookie. This is common in cases where forms are dynamically added to the page. To address this case, Django provides a view decorator which forces setting of the cookie: ensure_csrf_cookie().

Decorators

Handwrite Notes

  1. CORS: When site A wants to access content from another site B, it is called a Cross-Origin request. As it is disabled for security reasons, B sends an Access-Control-Allow-Origin header in the response. By default, a domain is not allowed to access an API hosted on another domain. The Origin header should be in request.

    django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS).

  2. How to correctly set a user password:

     def save(self, commit=True):
         user = super().save(commit=False)
         user.set_password(self.cleaned_data['password'])
         if commit:
             user.save()
         return user
    

Forms

How to write a minimal form in Django

Read the doc

<!-- polls/templates/polls/detail.html -->
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
    <legend><h1>{{ question.question_text }}</h1></legend>
    {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
    {% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
        <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
    {% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
# polls/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from .models import Choice, Question

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

Above codes are available in gists

A simple form in Django

Read the doc

# forms.py
from django import forms

class NameForm(forms.Form):
    your_name = forms.CharField(label='Your name', max_length=100)
<!-- index.html -->
<form action="/your-name/" method="post">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="Submit">
</form>
# views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render

from .forms import NameForm

def get_name(request):
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            # ...
            # redirect to a new URL:
            return HttpResponseRedirect('/thanks/')

    # if a GET (or any other method) we'll create a blank form
    else:
        form = NameForm()

    return render(request, 'name.html', {'form': form})

Above codes are available in gists

Bound and unbound form instances

Access form values

v = form.cleaned_data['my_form_field_name']

Custom Validators

A validator is a callable object or function that takes a value and returns nothing if the value is valid or raises a ValidationError if not

slug = forms.CharField(validators=[validators.validate_slug])

The clean_<fieldname>() method is called on a form subclass – where <fieldname> is replaced with the name of the form field attribute. This method does any cleaning that is specific to that particular attribute, unrelated to the type of field that it is. This method is not passed any parameters. You will need to look up the value of the field in self.cleaned_data and remember that it will be a Python object at this point, not the original string submitted in the form (it will be in cleaned_data because the general field clean() method, above, has already cleaned the data once).

#forms.py
from django.forms import ModelForm, ValidationError  # Import ValidationError
from .models import Palindrome

class PalindromeForm(ModelForm):
    def clean_word(self):
        # Get the user submitted word from the cleaned_data dictionary
        data = self.cleaned_data["word"]

        # Check if the word is the same forward and backward
        if data != "".join(reversed(data)):
            # If not, raise an error
            raise ValidationError("The word is not a palindrome")

        # Return data even though it was not modified
        return data

    class Meta:
        model = Palindrome
        fields = ["word"]

ModelForm

class ArticleForm(ModelForm):
    class Meta:
        model = Article
        fields = ['pub_date', 'headline', 'content', 'reporter']

To save the form, call form.save(). This will return the created object.

If we want to not immediately save the object to the database, we can call form.save(commit=False). This will return an object that hasn’t yet been saved to the database. This is useful if we want to do custom processing on the object before saving it, or if we want to use one of the specialized model saving options.

save_m2m() is another method that is provided by ModelForm that gives us the ability to save the many-to-many relationships along with the object.

Authentication

Authentication Settings

Authentication Views

urlpatterns = [
    path("accounts/", include("django.contrib.auth.urls")),
]

This will include the following URL patterns:

accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']

If you want more control over your URLs, you can reference a specific view in your URLconf:

urlpatterns = [
    path(
        "change-password/",
        auth_views.PasswordChangeView.as_view(template_name="change-password.html"),
    ),
]

is_authenticated

if request.user.is_authenticated:
    # Do something for authenticated users.
else:
    # Do something for anonymous users.

How to log a user in

To log a user in, from a view, use login(). It takes an HttpRequest object and a User object. login() saves the user’s ID in the session, using Django’s session framework.

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST["username"]
    password = request.POST["password"]
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        # Redirect to a success page.
        ...
    else:
        # Return an 'invalid login' error me

How to log a user out

def logout_view(request):
    logout(request)
    # Redirect to a success page.

Decorators

Django Admin

Register Models

from django.contrib import admin
from core.models import Blog

@admin.register(Blog)
class BlogAdmin(admin.ModelAdmin):
    pass

Tip: You can use UserAdmin for the User model.

Customizing Models

Adding the ordering attribute will default all queries on Person to be ordered by last_name then first_name.

class Person(models.Model):
    # ...
    class Meta:
        ordering = ("last_name", "first_name")
    # ...

It can also reference a method in the admin.ModelAdmin itself:

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ("last_name", "first_name", "show_average")

    def show_average(self, obj):
        from django.db.models import Avg
        result = Grade.objects.filter(person=obj).aggregate(Avg("grade"))
        return result["grade__avg"]

show_average() is called once for each object displayed in the list.

Anything the user types in the search box is used in an OR clause of the fields filtering the QuerySet. By default, each search parameter is surrounded by % signs. You can be more precise by specifying a __ modifier on the search field.

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    search_fields = ("last_name__startswith", )

Inlines

# OR use -> admin.StackedInline
class BookInline(admin.TabularInline):
    model = Book
    extra = 3 # Number of empty slots

class AuthorAdmin(admin.ModelAdmin):
    inlines = [BookInline]

For many-to-many relations we should use this:

class Film(Model):
    director = ManyToManyField('Director')
class DirectorInline(admin.TabularInline):
    model = Film.director.through

class FilmAdmin(admin.ModelAdmin):
    inlines = (
        DirectorInline,
        )

Actions

class ArticleAdmin(admin.ModelAdmin):
    actions = ["make_published"]

    @admin.action(description="Mark selected stories as published")
    def make_published(self, request, queryset):
        queryset.update(status="p")

HttpRequest

Attribute Description Examples
scheme URL scheme “http” or “https”
path Path portion of the URL “/music/bands/”
method HTTP method used “GET” or “POST”
GET Query string parameters <QueryDict: {'band_id':['123']}>
POST Fields from an HTTP POST <QueryDict: {'name':['Bob']}>
user Object describing the user  

Http Method Decorators

The decorators in django.views.decorators.http can be used to restrict access to views based on the request method. These decorators will return a django.http.HttpResponseNotAllowed if the conditions are not met.

  1. require_http_methods(request_method_list)
     from django.views.decorators.http import require_http_methods
    
     @require_http_methods(["GET", "POST"])
     def my_view(request):
         # I can assume now that only GET or POST requests make it this far
         pass
    
  2. require_GET()
  3. require_POST()
  4. require_safe()

    Decorator to require that a view only accepts the GET and HEAD methods. These methods are commonly considered “safe” because they should not have the significance of taking an action other than retrieving the requested resource.

Generic Views

Attributes and Methods

Cursor Pagination

URL Dispatcher

from news import views

path("archive/", views.archive, name="news-archive")

you can use any of the following to reverse the URL:

# using the named URL
reverse("news-archive")

Redirect

The arguments could be redirect():

  1. A model: the model’s get_absolute_url() function will be called.
  2. A view name, possibly with arguments: reverse() will be used to reverse-resolve the name.
  3. An absolute or relative URL, which will be used as-is for the redirect location.

Flash Messages

Add and use message

To add a message, call:

from django.contrib import messages

messages.add_message(request, messages.INFO, "Hello world.")
{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

Message_TAGS

Default:

{
    messages.DEBUG: "debug",
    messages.INFO: "info",
    messages.SUCCESS: "success",
    messages.WARNING: "warning",
    messages.ERROR: "error",
}

Override:

from django.contrib.messages import constants as message_constants

MESSAGE_TAGS = {message_constants.INFO: ""}

Template Language

Reference1 Reference2

Filter

Tip

<h1>Number of posts: {{ posts.count }}</h1>
<h1>Number of posts: {{ posts|length }}</h1>

Actually, in this very specific case, using the length template filter - which just calls len() - would be more efficient. That’s because calling .count() on a queryset that hasn’t been evaluated causes it to go back to the database to do a SELECT COUNT, whereas len() forces the queryset to be evaluated.

Custom Template Tags and Filters

First Step

polls/
    __init__.py
    models.py
    templatetags/
        __init__.py
        poll_extras.py
    views.py

Load Modules

In every templates that we want to use our custom tags:

{% load poll_extras %}

Register

To be a valid tag library, the module must contain a module-level variable named register that is a template.Library instance, in which all the tags and filters are registered. So, near the top of your module, put the following:

from django import template

register = template.Library()

Custom filters are Python functions that take one or two arguments:

Once you’ve written your filter definition, you need to register it with your Library instance, to make it available to Django’s template language:

register.filter("cut", cut)
register.filter("lower", lower)

The Library.filter() method takes two arguments:

You can use register.filter() as a decorator instead:

@register.filter(name="cut")
def cut(value, arg):
    return value.replace(arg, "")


@register.filter
def lower(value):
    return value.lower()

If you leave off the name argument, as in the second example above, Django will use the function’s name as the filter name.

Finally, register.filter() also accepts three keyword arguments, is_safe, needs_autoescape, and expects_localtime.

url

{% url 'some-url-name' arg1=v1 arg2=v2 %}

Context Processors

def site_settings(request):
    return {'site_name': 'My awesome site', 'site_creation_date': '12/12/12'}

# Add this to the context_processors list
'yourapp.context_processors.site_settings'  # <-- our custom context processor

Models

Methods

Abstract Model

If you want to define a model that you can reuse by deriving from it, abstract base classes are the way to go.

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True

Choices

The first element in each tuple is the value that will be stored in the database. The second element is displayed by the field’s form widget.

YEAR_IN_SCHOOL_CHOICES = [
    ("FR", "Freshman"),
    ("SO", "Sophomore"),
    ("JR", "Junior"),
    ("SR", "Senior"),
    ("GR", "Graduate"),
]

Integer choices:

class Card(models.Model):
    class Suit(models.IntegerChoices):
        DIAMOND = 1
        SPADE = 2
        HEART = 3
        CLUB = 4

    suit = models.IntegerField(choices=Suit.choices)

Field Type Parameters

Deep Copy

Just change the primary key of your object and run save().

obj = Foo.objects.get(pk=<some_existing_pk>)
obj.pk = None
obj.save()

Manager

Manager Names

Using this example model, Person.objects will generate an AttributeError exception, but Person.people.all() will provide a list of all Person objects.

from django.db import models


class Person(models.Model):
    # ...
    people = models.Manager()

Extra Manager

Adding extra Manager methods is the preferred way to add table-level functionality to your models. (For row-level functionality – i.e., functions that act on a single instance of a model object – use Model methods, not custom Manager methods.)

For example, this custom Manager adds a method with_counts():

from django.db import models
from django.db.models.functions import Coalesce


class PollManager(models.Manager):
    def with_counts(self):
        return self.annotate(num_responses=Coalesce(models.Count("response"), 0))


class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    objects = PollManager()

Modifying a manager’s initial QuerySet

You can override a Manager’s base QuerySet by overriding the Manager.get_queryset() method.

class DahlBookManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(author="Roald Dahl")

Default managers

Django interprets the first Manager defined in a class as the default Manager. You can specify a custom default manager using Meta.default_manager_name.

Field lookups

  1. gt
  2. gte
  3. lt
  4. lte
  5. startswith: abc%
  6. istartswith: Case-insensitive version of startswith
  7. endswith: %abc
  8. contains: %abc%
  9. in: WHERE id IN (1, 3, 4)

Aggregate

Person.objects.aggregate(
    average=Avg("age"),
    max_age=Max("age"),
    min_age=Min("age"),
    sum_age=Sum("age"),
    count=Count("age"),
    )

Relations

OneToMany

By default, this Manager is named FOO_set, where FOO is the source model name, lowercased. This Manager returns QuerySets.

You can override the FOO_set name by setting the related_name parameter in the ForeignKey definition.

>>> b = Blog.objects.get(id=1)
>>> b.entries.all()  # Returns all Entry objects related to Blog.

# b.entries is a Manager that returns QuerySets.
>>> b.entries.filter(headline__contains="Lennon")
>>> b.entries.count()

ManyToMany

from django.db import models


class Publication(models.Model):
    title = models.CharField(max_length=30)

    class Meta:
        ordering = ["title"]

    def __str__(self):
        return self.title


class Article(models.Model):
    headline = models.CharField(max_length=100)
    publications = models.ManyToManyField(Publication)

    class Meta:
        ordering = ["headline"]

    def __str__(self):
        return self.headline

Add or Create:

>>> a2.publications.add(p1, p2)
>>> a2.publications.create(title="Science News")

OneToOne

class EntryDetail(models.Model):
    entry = models.OneToOneField(Entry, on_delete=models.CASCADE)
    details = models.TextField()

ed = EntryDetail.objects.get(id=2)
ed.entry  # Returns the related Entry object.
e = Entry.objects.get(id=2)
e.entrydetail  # returns the related EntryDetail object (Reverse)

If no object has been assigned to this relationship, Django will raise a DoesNotExist exception.

Transaction

Atomic

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()
with transaction.atomic():
    user = User.objects.create_user(username=username, password=password)
    Profile.objects.create(
        user=user,
        nickname=request.POST.get('nickname'),
        bio=request.POST.get('bio'),
        location=request.POST.get('location'),
        weight=request.POST.get('weight'),
        website=request.POST.get('website'),
    )

Django Rest Framework

Serializer

Serializer

Custom create, update and validation functions.

class SnippetSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)

    def create(self, validated_data):
        """
        Create and return a new `Snippet` instance, given the validated data.
        """
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `Snippet` instance, given the validated data.
        """
        instance.title = validated_data.get('title', instance.title)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.save()
        return instance

ModelSerializer

Very looks like model forms:

rom rest_framework import serializers
from .models import Product

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'
        # Other attributes
        exclude = ['users']
        depth = 1  # Specifying nested serialization

Custom Method Field

class PostSerializer(serializers.ModelSerializer):
    owner = serializers.SerializerMethodField()
    class Meta:
        model = Post
        fields = ('title', 'body', 'created', 'owner')

    def get_owner(self, obj):
        return obj.owner.username

Serializer Fields

ViewSet

First of all let’s refactor our UserList and UserDetail views into a single UserViewSet. We can remove the two views, and replace them with a single class:

from rest_framework import viewsets

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    This viewset automatically provides `list` and `retrieve` actions.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

Actions

@action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, request, *args, **kwargs):
    snippet = self.get_object()
    return Response(snippet.highlighted)

def list(self, request):
    pass

def create(self, request):
    pass

def retrieve(self, request, pk=None):
    pass

def update(self, request, pk=None):
    pass

def partial_update(self, request, pk=None):
    pass

def destroy(self, request, pk=None):
    pass

Router

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views

# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet,basename="snippet")
router.register(r'users', views.UserViewSet,basename="user")

# The API URLs are now determined automatically by the router.
urlpatterns = [
    path('', include(router.urls)),
]

Registering the viewsets with the router is similar to providing a urlpattern. We include two arguments - the URL prefix for the views, and the viewset itself.

Views

Function Based Views

from .models import Product
from .serializers import ProductSerializer
from rest_framework.response import Response
from rest_framework.decorators import api_view


@api_view(['GET'])
def my_api(request):
    instance = Product.objects.all()
    data = ProductSerializer(instance, many=True).data
    return Response(data)

APIView

APIView classes are different from regular View classes in the following ways:

RetrieveAPIView

Used for read-only endpoints to represent a single model instance. Provides a get method handler.

from rest_framework import generics
from .models import Product
from .serializers import ProductSerializer

class MyAPIView(generics.RetrieveAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
path('<int:pk>', views.MyAPIView.as_view())

CreateAPIView

Used for create-only endpoints. Provides a post method handler.

You can override the save method and customize what data is saved. For example:

def perform_create(self, serializer):
    serializer.save(owner=self.request.user)

The owner content will override.

ListAPIView

Used for read-only endpoints to represent a collection of model instances. Provides a get method handler.

ListCreateAPIView

Used for read-write endpoints to represent a collection of model instances. Provides get and post method handlers.

Serializer Relations

SlugRelatedField

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.SlugRelatedField(
        many=True,
        read_only=True,
        slug_field='title'
     )

    class Meta:
        model = Album
        fields = ['album_name', 'artist', 'tracks']

HyperlinkedRelatedField

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='track-detail'
    )

    class Meta:
        model = Album
        fields = ['album_name', 'artist', 'tracks']

Requests

  1. .data: returns the parsed content of the request body.

Authentication

Token Authentication

Change settings:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ]
}
Generate Token

This view will return a JSON response with the token. The token is a string of random characters, and is unique to the user. This view gets username and password.

from rest_framework.authtoken.views import obtain_auth_token

urlpatterns += [
    path('api-token-auth/', obtain_auth_token)
]

Django Environment

  1. DJANGO_SETTINGS_MODULE: When you use Django, you have to tell it which settings you’re using.

django-environ

Quick Start