DEV Community

loading...
Cover image for My beloved Django cheat sheet

My beloved Django cheat sheet

ericchapman profile image Eric Chapman Updated on ・6 min read

Start a new Django project

# Create et access project folder
~$  mkdir project_name
~$  cd project_name

# Create Python virtual env 
~$  python3 -m venv venv

# Activate virtual env
~$  source venv/bin/activate

# Deactivate virtual env
~$  deactivate

# If requirements already exist
~$  pip install -r requirements.txt

# Freeze requirements in a file
~$  pip freeze > requirements.txt

# Install django
~$  pip install django~=3.1.0 

# New django project (from project_name folder)
~$  django-admin startproject config .

# Create app (from project_name folder)
~$  python manage.py startapp app_name

# Migration
~$  python manage.py makemigrations 
~$  python manage.py migrate

# Create superuser
~$  python manage.py createsuperuser

# Start server
~$  python manage.py runserver  => ex.  http://127.0.0.1:8000

# Current project shell example
~$ python manage.py shell
 >>> from app_name.models import User
 >>> user1 = User.objects.first()

# Prepare static folders fpor production
$ python manage.py collectstatic

# Take all data from app blog and export in json
python manage.py dumpdata blog >myapp.json

# Take all data in json file and import in app data table
python manage.py loaddata myapp.json

Enter fullscreen mode Exit fullscreen mode

Project config

# Add app to settings.py
INSTALLED_APPS = [  , 'app_name' ]

# App templates folder
create folder appfolder/templates/appname

# Project templates folder: 
create folder projectname/templates

# settings.py template config
Project templates settings.py: 
    TEMPLATES = [
        { 
                'DIRS': [BASE_DIR / 'templates', ],
         }

# Create Static folder: 
project_name\static\

# Static folder (settings.py): 
STATIC_URL = '/static/'
STATICFILES_DIRS = [ BASE_DIR / 'static' ] 
STATIC_ROOT = 'static_root'

# To use PostgresSQL
# pip install psycopg2
# settings.py
DATABASE = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'blog',
        'USER': 'admin',
        'PASSWORD': '123456',
        'HOST': 'localhost',
        'PORT': '5432'
Enter fullscreen mode Exit fullscreen mode

Create data model

# models.py 
from django.db import models

class Customer(models.Model):

    # database, display
    TYPE_CHOICES = (
        ('Customer', 'Customer'),
        ('Supplier', 'Supplier'),
        ('Student', 'Student'),
    )

    name = models.Charfield('Article name', max_length=120)
    note = models.TextField(blank=True, null = True)
    email = models.EmailField(max_length=255, blank=True, null=True)
    credit = models.FloatField(blank=True)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    type = models.CharField(choices=TYPE_CHOICES)

    def __str__(self): 
        return self.name

# User for Auth and more
# Add to settings.py: AUTH_USER_MODEL = 'app_name.User'
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
    # Inherits AbstractUser fields
    pass

# One-to-Many: (use double quotes if the entity is not yet declare) ex. "Supplier"
supplier = models.ForeignKey(Supplier, blank=True, null=True, on_delete=models.CASCADE)

# Many-to-Many: 
tags = models.ManyToManyField(Tag, blank=True)

# One to One 
User = models.OneToOneField(User, on_delete=models.CASCADE)

# Overwrite save method
def save(self, (*args, **kwargs):
    if not self.slug:
        self.slug = slugify(self.title)

    super().save(*args, **kwargs)
Enter fullscreen mode Exit fullscreen mode

Admin panel

# admin.py
from .models import Blog
admin.site.register(Blog)

# Custom model Admin (admin.py): 
class BlogAdmin(admin.ModelAdmin)
    list_display = ("title", "description")
    ordering("date_created",)
    search_fields("title", "description")

# Register app
admin.site.register(Blog, BlogAdmin)
Enter fullscreen mode Exit fullscreen mode

Routing

# APP URLS 
# create urls.py in app_name folder
from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static

url patterns = [ 
    path('posts', views.index, name='posts.index'),
    path('posts/create/', views.create, name='posts.create',
    path('posts/<int:id>/', views.show, name='posts.show'),
    path('posts/<int:id>/edit/', views.edit, name='posts.edit'),
    path('posts/<int:id>/delete/', views.delete, name='posts.delete'),
] 

# URL Route ex. names conventions
posts.index | posts.create | posts.edit | posts.delete | posts.show

# PROJECT URLS 
# Include the app urls into the project urls (project_name/urls.py) 
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('app_name.urls'))
]

# Production Static route
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Enter fullscreen mode Exit fullscreen mode

Function Based Views

# views.py
from django.shortcuts import render, redirect
from .models import Post
from .forms import PostForm

def index(request):
    # Get all Posts
    posts = Post.objects.all()

    # Render app template
    return render(request, 'appfolder/index.html', {'posts': posts})

def show(request, id):
    post = Post.objects.get(id=id)
    return render(request, 'appfolder/show.html', {'post': post})

def create(request):
    form = PostForm(request.POST or None)
    if form.is_valid():
        # optionally we can access form data with form.cleaned_data['first_name']
        form.save()
        return redirect('/posts')

    return render(request, 'appfolder/create.html', {'form': form)

def edit(request, id):
    post = Post.objects.get(id=id)
    form = PostForm(request.POST or None, instance=post)
    if form.is_valid():
        form.save()
        return redirect('/posts')

    return render(request, 'appfolder/edit.html', {'form': form)

def delete(request, id):
    post = Post.objects.get(id=id)
    post.delete()
    return redirect('/posts')
Enter fullscreen mode Exit fullscreen mode

Class based Views

from django.views.generic import TemplateView, ListView, DetailView, CreateView, UpdateView, DeleteView

class LandingPageView(TemplateView):
    template_name = 'landing.html'

    # change context data dict
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Landing Page'
        return context

class PostsListView(ListView):
    model = Post 
    # or 
    queryset = Post.objects.all() 

    # var name object_list (or post_list) will be available in template
    # context_object_name = "posts" to change object list var name

    # by default the view will open post/post_list.html but that can be change
    template_name = 'posts/post_list.html'

class PostsDetailView(DetailView):
    model = Post # object var in template

    # by default the view will try to open post/post_detail.html 
    template_name = 'posts/post_detail.html'


class PostsCreateView(CreateView):
    form_class = PostForm
    template_name = 'posts/post_create.html'

    # default return is detail view
    def get_success_url(self):
        return reverse('posts-list')

    # we can overwrite form data
    def form_valid(self, form):
        if self.request.user.is_authenticated:
            from.instance.author = self.request.user

        return super().form_valid(form)

class PostsUpdateView(UpdateView):
    model = Post
    form_class = PostForm
    template_name = 'posts/post_update.html'
    def get_success_url(self):
        return reverse('post-list')

    # change context data dict
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['submit_text'] = 'Update'
        return context


class PostsDeleteView(DeleteView):
    model = Post
    template_name = 'posts/post_delete.html'
    success_url = reverse_lazy('posts-list')

# Urls.py route declaration
path('<int:pk>/update/', PostsUpdateView.as_view(), name='post-update')
Enter fullscreen mode Exit fullscreen mode

Django Template

{% extends 'base.html' %}
{% block content %}     {% endblock %} 
{% include 'header.html' %} 
{% if %}   {% else %}   {% endif %} 
{% for x in y %}   {% endfor %} 
{{ var_name }}

Template variables formating
{{ title | lower }} 
{{ blog.post | truncatwords:50 }}
{{ order.date | date:"D M Y" }}
{{ list_items | slice:":3" }}
{{ total | default:"nil" }}

Current path (ex. posts/1/show)
{{ request.path }}   

URL by name with param
{% url 'posts.delete' id=post.id %}

Use static in template: 
{% load static %}
{% static 'css/main.css' %} 
Enter fullscreen mode Exit fullscreen mode

ORM Data manipulation (CRUD)

# Create
article = Article(name='Item 1', price=19.95)

# Save
article.save()

# One line create and save
Article.objects.create(name='Item 1', price=19.95) 

# Read all
Article.objects.all()

# Read one
Article.objects.get(id=1) 

# Select Related (to avoid n+1 query)
posts = Post.objects.select_related('user', 'category').all()

# Read or 404 
articles = Article.get_object_or_404(Article, id=502)    # render template/404.html

# Filter 
Article.objects.filter(model='dyson', name__icontains='dyson') # __icontains    
Article.objects.filter(year__gt=2016) # __gt = greater than

# Ordering 
Article.objects.order_by('name')     # ascending
Article.objects.order_by('-name')   # descending

# Slicing return first
Article.objects.all().order_by('name')[0]

# Slicing return last
Article.objects.all().order_by('-name')[0]

# Slicing limit/offset
Article.objects.all().order_by('name')[1..10]

# Updating
article = Article.objects.first()
article.name = 'new name'
article.save()

# One line update
Article.objects.filter(id=4).update(name='new name')

# Deleting
article = Article.objects.first()
article..delete()

# One line delete
article.objects.get(id=1).delete()

# Delete all
Article.objects.all().delete()

# Set ForeignKey field value
model1 = Model(name='dyson')
article.model = model1

# Get ForeignKey value
article1.model.name
model1.article_set.all()

# Add Many-to-Many
article1.tags.add(tag1) 
article1.tags.all()
tag1.articles_set.all()
Enter fullscreen mode Exit fullscreen mode

Form (forms.py)

from django import forms
class ArticleForm(forms.Form): 
    name = forms.Charfield(max_length=100)
    description = forms.Charfield(blank=True, null = True)


# Model Form 
from django.forms import ModelForm
from .models import Article
class ArticleForm(ModelForm)
    class Meta:
        Model = Article
        fields = ['name', 'description', 'price']


# Render form in template
<form method=post action=“” novalidate> 
    {% csrf_token %}
    {{ form }} 
    <button type="submit">Submit</button>
</form>

# Bootstrap (pip install django-crispy-forms + installed_apps: 'crispy_forms')
{% load crispy_forms_tags %}
{{ form|crispy }}
{{ form.email|as_crispy_field }}
Enter fullscreen mode Exit fullscreen mode

Flash messages

messages.success(request, 'Login successful')
messages.error(request, 'Login error')

# Message tags
# debug, info, success, warning and error

# Display flash in template 
{% if messages %} 
    {% for message in messages %} 
        {% message %} 
        {% message.tags %}
Enter fullscreen mode Exit fullscreen mode

Authentification

# Project URLS 
# Create all auth routes
from django.contrib.auth.views import LoginView, LogoutView
from posts.views import SignupView

# Include all auth routes
path('account/', include('django.contrib.auth.urls')),

# Some example of auth routes
# path('account/login/', LoginView.as_view(), name='login'),
# path('account/logout/', LogoutView.as_view(), name='logout'),
# path('account/signup/', SignupView.as_view(), name='signup'),

# Views
# LoginView and LogoutView already exist in django.contrib.auth.views
# custom SignupView:
class SignupView(generic.CreateView):
    template_name = 'registration/signup.html'
    form_class = CustomUserCreationForm

    def get_success_url(self):
        return reverse("login")

# Forms
# Login form already exist
# Custom signup form:
from django.contrib.auth.forms import UserCreationForm, UsernameField

User = get_user_model()

class CustomUserCreationForm(UserCreationForm):
    class Meta:
        model = User
        fields = ("username",)
        field_classes = {'username': UsernameField}

# settings.py 
LOGIN_REDIRECT_URL = '/posts'
LOGIN_URL = '/login'

# templates
# registration/login.html
{% extends "base.html" %}
{% block content %}
    <form method="post">
        {% csrf_token %}
        {{ form }}
        <button type="submit">Login</button>
    </form>
{% endblock content %}

# registration/signup.html
{% extends "base.html" %}
{% block content %}
    <form method="post">
        {% csrf_token %}
        {{ form }}
        <button type="submit">Signup</button>
    </form>
{% endblock content %}

# Authentication links
<a href="{% url 'login' %}">Login</a>
<a href="{% url 'signup' %}">Signup</a>
<a href="{% url 'logout' %}">Logout</a>

# Auth in template
{% if request.user.is_authenticated %}
    Logged in as: {{ request.user.username }}
{% endif %}

# Restrict views to auth user only
# views.py
from django.contrib.auth.mixins import LoginRequiredMixin

class PostsCreateView(LoginRequiredMixin, generic.CreateView):
   ...
   ...

# Function base view auth
def login(request):
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        user = authenticate(request, username=username, password=password)
        if user is not None:
            log_user(request, user)
            return redirect("index")

return render(request, "registration/login.html", {})
Enter fullscreen mode Exit fullscreen mode

Signals

# models.py
from django.db.models.signals import post_save, pre_save

def post_user_created_signal(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)


# Launch the post_user_create_singal method if User model is save
post_save.connect(post_user_created_signal, sender=User)
Enter fullscreen mode Exit fullscreen mode

Discussion (9)

pic
Editor guide
Collapse
janmpeterka profile image
Jan Peterka (he/him)

NIce! Just want to say - switched to pipenv from pip+venv and oh my, does it make my life easier!

Collapse
ericchapman profile image
Eric Chapman Author

Yes good advice! I use pipenv too but for the cheat sheet I decide to go for the native way.

Collapse
karthik2265 profile image
Karthik suryadevara

hey, eric
Nice post
I want to learn Django I know python very well.
could you point me towards some resources and advice on how to master django?

Collapse
ericchapman profile image
Eric Chapman Author

Hi,

One of the best Django learning site: learn.justdjango.com/roadmaps/djan...

All the basic stuff is free. Hours and hours of great videos.

Collapse
karthik2265 profile image
Karthik suryadevara

Thanks 👍🏻

Collapse
careuno profile image
Carlos Merchán

nice, thanks!

Collapse
devparkk profile image
Dev Prakash

Brilliant work 🙌👌

Collapse
yuhuishishishi profile image
I love integers

Precise and yet very comprehensive. Thanks

Collapse
adeborat profile image
adeborat

Very useful, thanks