Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.
Django’s online documentation is a great source of information, but sometimes you’d rather glance quickly at an example. This Django cheat sheet has some sample code. Just grab it and go!
Start a new Django project
Copied!# 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 # If you want to deactivate virtual env ~$ deactivate # Install django (~= same as 3.1.*) ~$ 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:
Django create a database table for each models present in your app using thoses commands:
- Makemigrations: Create a file under app_name/migrations with the database structure to create
Copied!~$ python manage.py makemigrations
- Migrate: Will read the migrations files and create the actual database and tables
Copied!~$ python manage.py migrate
Create superuser for authenficiation/admin panel
Copied!~$ python manage.py createsuperuser
Start Django Server
Copied!~$ python manage.py runserver => ex. http://127.0.0.1:8000
Requirements
Copied!# Create a requirements file that contain all your projet dependencies ~$ pip freeze > requirements.txt # Install your project requirements (if a requirements file exist) ~$ pip install -r requirements.txt
Other commands
Copied!# Django shell (Run projet code direclty) ~$ python manage.py shell # example of code to run in the shell: >>> from app_name.models import User >>> user1 = User.objects.first() # Prepare static folders for 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
Project config
Copied!# 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_namestatic # 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'
Create data model:
Theses models can be created as database tables with the migrations commands
Copied!# models.py # The id fields is automaticly created by Django for each model that why it's not show below from django.db import models class Customer(models.Model) name = models.Charfield('Customer', max_length=120) age = models.IntegerField() 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) # Select Field (return value, display value) TYPE_CHOICES = ( ('Customer', 'Customer'), ('Supplier', 'Supplier'), ('Student', 'Student'), ) type = models.CharField(choices=TYPE_CHOICES)
Model string representation
Copied!class Customer(models.Model): name = models.Charfield('Customer', max_length=120) age = models.IntegerField() def __str__(self): return self.name
Relationship between models
Copied!# 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) # on_delete can be set to models.CASCADE, models.ST_DEFAULT or models.SET_NULL # 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)
Admin panel:
Every Django projects come with an Admin Panel that can be open at /admin url (ex: localhost:8000/admin), To display the model in the Admin panel register the model in the app_name/admin.py file
Copied!from .models import Blog admin.site.register(Blog)
Customize Admin Panel
For each models you can specify the fields you want to use
Copied!# Custom model Admin (admin.py): class BlogAdmin(admin.ModelAdmin) fields = ("title", "description") # Fields to use for add/edit/show page list_display = ("title", "description") # fields to display in search page list_display_links = ("title") # fields that will be a link in search page ordering("date_created",) # Ordering allowed in the search page search_fields("title", "description") # Search fields allowed in the search page # Register app admin.site.register(Blog, BlogAdmin)
Routing:
Django routing info is store in project_folder/urls.py file
Copied!from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), # pre-created admin urls routes path('', include('app_name.urls')) # include your app urls ]
the ‘include()’ method allow to link another urls.py file created in your app folder (app_name/urls.py)
Copied!from django.urls import path from . import views 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'), ]
Static route
Copied!from django.conf import settings from django.conf.urls.static import static urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Function Based Views
Copied!# 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 with context 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'] post = form.save(commit=False) post.user = request.user post.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')
Class based Views
Copied!from django.views.generic import TemplateView, ListView, DetailView, CreateView, UpdateView, DeleteView class LandingPageView(TemplateView): template_name = 'landing.html' # Optional: 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): queryset = Post.objects.all() # Optional # context_object_name = "posts" (default: post_list) # template_name = 'posts.html' (default: posts/post_list.html) class PostsDetailView(DetailView): model = Post # object var in template # Optional # template_name = 'post.html' (default: posts/post_detail.html) class PostsCreateView(CreateView): form_class = PostForm template_name = 'posts/post_create.html' # no default value def get_success_url(self): return reverse('posts-list') # Optional: Overwrite form data (before save) 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') # Optional: 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')
Django Template:
Templates are store in project_folder/templates or in your app_folder/templates/app_name/*.html
Copied!{% extends 'base.html' %} {% block content %} {% endblock %} {% include 'header.html' %} {% if user.username = 'Mike' %} <p>Hello Admin</p> {% else %} <p>Hello User</p> {% endif %} {% for product in products %} <p>The product name is {{ product }}<p> {% 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' %}
Model Managers and Querysets:
Model manager allow model database reads and writes
Copied!# One line create and save Article.objects.create(name='Item 1', price=19.95) # Read all Article.objects.all() # Create user = User.objects.first() article = Article(user=user, name='Item 1', price=19.95) # Save article.save() # Read one Article.objects.get(id=1) # Select Related (to avoid n+1 query) posts = Post.objects.select_related('user', 'category').all() # Read or render a 404 not found page from django.shortcuts import get_object_or_404 article = get_object_or_404(Article, id=512) # Filter Article.objects.filter(model='dyson', name__icontains='dyson') # __icontains Article.objects.filter(year__gt=2016) # __gt = greater than Article.objects.filter(year__lt=2001) # __lt = less than # Filter on relationship sub model field Article.objects.get(user__username='mike') # 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()
Form (forms.py)
Copied!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'] # Use '__all__' for all fields # 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 }} # crispy-tailwind pip install crispy-tailwind # settings.py CRISPY_ALLOWED_TEMPLATE_PACKS = 'tailwind' CRISPY_TEMPLATE_PACK = 'tailwind' # template usage {% load tailwind_filters %} {{ form|crispy}}
Form validation
Copied!# forms.py from django.core.exceptions import ValidationError # field validation def clean_first_name(self): data = self.cleaned_data['first_name'] if data = 'Mike': raise ValidationError('Your name must not be Mike') return data # form validation def clean(self): first_name = self.cleaned_data['first_name'] last_name = self.cleaned_data['last_name'] if first_name + last_name = 'MikeTaylor': raise ValidationError('Your name must not be Mike Taylor')
Flash messages
Copied!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 %}
User model (pre-created)
Copied!# Get a reference to Django pre-created User model from django.contrib.auth import get_user_model User = get_user_model() # Or if you want to custom user model from django.contrib.auth.models import AbstractUser class User(AbstractUser): # add custom fields and methods # To make Django use that model go to settings.py and add: AUTH_USER_MODEL = 'app_name.User'
Authentification: LoginView
Copied!# LoginView is already pre-created by Django from django.contrib.auth.views import LoginView # Add a url to reach that view path('login/', LoginView.as_view(), name='login') # By default the LoginView will try to open a template name 'registration/login.html' and send a login form with it. # Create a template under registration/login.html {% extends "base.html" %} {% block content %} <form method="post"> {% csrf_token %} {{ form }} <button type="submit">Login</button> </form> {% endblock content %} # When user click the Login button, the LoginView will try to authenticate the user with the form username ans password. # If successful il will then login the user and redirect to LOGIN_REDIRECT_URL specified in your settings.py
Authentification: LogoutView
Copied!# LogoutView is already pre-created by Django from django.contrib.auth.views import LogoutView # Add a url to reach that view path('logout/', LoginView.as_view(), name='logout') # Include a link in a template <a> href="{% url 'logout' %}">Logout</a> # After link is execute, the user will be logout and redirect to LOGOUT_REDIRECT_URL specified in your settings.py
Authentification: SignupView
Copied!# Create a SignupView (that view is not created by default) # import sinupview form pre-created by Django from django.contrib.auth.forms import UserCreationForm from django.views.generic import CreateView class SignupView(CreateView): template_name = 'registration/signup.html' form_class = UserCreationForm def get_success_url(self): return reverse("login") # Create template: registration/signup.html {% extends "base.html" %} {% block content %} <form method="post"> {% csrf_token %} {{ form }} <button type="submit">Signup</button> </form> {% endblock content %} # Add a url to reach that view from posts.views import SignupView path('signup/', SignupView.as_view(), name='signup') # Optional: Customize the UserCreationForm # (forms.py) from django.contrib.auth import get_user_model from django.contrib.auth.forms import UserCreationForm User = get_user_model() class CustomUserCreationForm(UserCreattionForm): class Meta: model = User fields = ['username'] fields_classes = {'username': UsernameField}
Optional pre-created authentification routes
Copied!# urls.py urlpatterns += path('', include('django.contrib.auth.urls')) # /login, /lougout, /signup, etc.
Template Authentification helpers
Copied!# Authentication links <a href="{% url 'login' %}">Login</a> <a href="{% url 'signup' %}">Signup</a> <a href="{% url 'logout' %}">Logout</a> # Check if user login {% if request.user.is_authenticated %} Logged in as: {{ request.user.username }} {% endif %}
Authorization: LoginRequiredMixin and login_required
Copied!from django.contrib.auth.mixins import LoginRequiredMixin # Restrict views to auth user only (views.py) class PostsCreateView(LoginRequiredMixin, generic.CreateView): ... ... from django.contrib.auth.decorators import login_required @login_required(login_url='/login') def search_page(request): ... ...
Manual Authentification, Login and Logout
Copied!from django.contrib.auth import authenticate, login def login_page(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: login(request, user) return redirect("index") return render(request, "registration/login.html", Array) def logout_page(request): logout(request) return redirect("index")
User Change password
Copied!# set_password will hash the password user.set_password('raw password')
Send Email
Copied!# settings.py EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" # Send email function from django.core.email import send_mail send_mail( subject = "A new post has been created", messsage = "Go to the web site to see the detail", from_email = "test@test.com", recipient_list = ["test2@text.com"] )
Signals
Copied!# 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)
Seed
Copied!from .models import Product, Category from django.shortcuts import HttpResponse from faker import Faker def seed(request): Product.objects.all().delete() Category.objects.all().delete() category = Category() category.name = "Sports" category.save() category = Category() category.name = "Home" category.save() fake = Faker() for _ in range(100): product = Product() product.name = fake.unique.word() product.short_description = fake.sentence() product.main_picture = fake.image_url() product.price = fake.random_digit() * 10 product.category = Category.objects.order_by('?').first() product.save() return HttpResponse('Seeded')
.env key/value file
Copied!$ pip install django-dotenv
add code to manage.py file
Copied!import dotenv def main(): """Run administrative tasks.""" dotenv.read_dotenv() #add this line ... ...
Create a file name ‘.env’ in the root folder of your project
Copied!SECRET_KEY = 'your secret key' ALLOWED_HOST=127.0.0.1
In settings.py change security related settings to point to the .env file
Copied!import os SECRET_KEY = os.environ.get('SECRET_KEY') ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS')
Leave a Reply