Start a new Django project
~$ mkdir project_name ~$ cd project_name
~$ python3 -m venv venv
~$ source venv/bin/activate
~$ deactivate
$ pip install django=3.1.0
~$ django-admin startproject config .
~$ 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 ~$ python manage.py makemigrations Migrate: Will read the migrations files and create the actual database and tables ~$ python manage.py migrate Create superuser for authenficiation/admin panel ~$ python manage.py createsuperuser Start server ~$ python manage.py runserver => ex. http://127.0.0.1:8000 Requirements
~$ pip freeze > requirements.txt
~$ pip install -r requirements.txt Other commands
~$ python manage.py shell
from app_name.models import User user1 = User.objects.first()
$ python manage.py collectstatic
python manage.py dumpdata blog >myapp.json
python manage.py loaddata myapp.json
Project config
INSTALLED_APPS = [ … , 'app_name' ]
create folder appfolder/templates/appname
create folder projectname/templates
Project templates settings.py: TEMPLATES = [ { … 'DIRS': [BASE_DIR / 'templates', ], … }
project_name\static\
STATIC_URL = '/static/' STATICFILES_DIRS = [ BASE_DIR / 'static' ] STATIC_ROOT = 'static_root'
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
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 class Customer(models.Model): name = models.Charfield('Customer', max_length=120) age = models.IntegerField()
def __str__(self):
return self.name
Relationship between models
supplier = models.ForeignKey(Supplier, blank=True, null=True, on_delete=models.CASCADE)
tags = models.ManyToManyField(Tag, blank=True)
User = models.OneToOneField(User, on_delete=models.CASCADE)
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 from .models import Blog admin.site.register(Blog) Customize Admin Panel
For each models you can specify the fields you want to use
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
admin.site.register(Blog, BlogAdmin) Routing: Django routing info is store in project_folder/urls.py file 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) 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 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
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 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()
# 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
# 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')
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
{% extends 'base.html' %}
{% block content %}
{% endblock %}
{% include 'header.html' %}
{% if user.username = 'Mike' %}
Hello Admin
{% else %}
Hello User
{% endif %}{% for product in products %}
The product name is {{ product }}
{% 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
Article.objects.create(name='Item 1', price=19.95)
Article.objects.all()
user = User.objects.first() article = Article(user=user, name='Item 1', price=19.95)
article.save()
Article.objects.get(id=1)
posts = Post.objects.select_related('user', 'category').all()
from django.shortcuts import get_object_or_404 article = get_object_or_404(Article, id=512)
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
Article.objects.get(user__username='mike')
Article.objects.order_by('name') # ascending Article.objects.order_by('-name') # descending
Article.objects.all().order_by('name')[0]
Article.objects.all().order_by('-name')[0]
Article.objects.all().order_by('name')[1..10]
article = Article.objects.first() article.name = 'new name' article.save()
Article.objects.filter(id=4).update(name='new name')
article = Article.objects.first() article.delete()
article.objects.get(id=1).delete()
Article.objects.all().delete()
model1 = Model(name='dyson') article.model = model1
article1.model.name model1.article_set.all()
article1.tags.add(tag1) article1.tags.all() tag1.articles_set.all() Form (forms.py) from django import forms class ArticleForm(forms.Form): name = forms.Charfield(max_length=100) description = forms.Charfield(blank=True, null = True)
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
{% csrf_token %} {{ form }} Submit{% load crispy_forms_tags %} {{ form|crispy }} {{ form.email|as_crispy_field }}
pip install crispy-tailwind
CRISPY_ALLOWED_TEMPLATE_PACKS = 'tailwind' CRISPY_TEMPLATE_PACK = 'tailwind'
{% load tailwind_filters %} {{ form|crispy}} Form validation
from django.core.exceptions import ValidationError
def clean_first_name(self): data = self.cleaned_data['first_name'] if data = 'Mike': raise ValidationError('Your name must not be Mike')
return data
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 messages.success(request, 'Login successful') messages.error(request, 'Login error')
{% if messages %} {% for message in messages %} {% message %} {% message.tags %} User model (pre-created)
from django.contrib.auth import get_user_model
User = get_user_model()
from django.contrib.auth.models import AbstractUser
class User(AbstractUser): # add custom fields and methods
Authentification: LoginView
from django.contrib.auth.views import LoginView
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.
{% extends "base.html" %} {% block content %}
{% csrf_token %} {{ form }} Login {% 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
from django.contrib.auth.views import LogoutView
path('logout/', LoginView.as_view(), name='logout')
href="{% url 'logout' %}">Logout
After link is execute, the user will be logout and redirect to LOGOUT_REDIRECT_URL specified in your settings.py
Authentification: SignupView
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")
{% extends "base.html" %} {% block content %}
{% csrf_token %} {{ form }} Signup {% endblock content %}from posts.views import SignupView
path('signup/', SignupView.as_view(), name='signup')
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
urlpatterns += path('', include('django.contrib.auth.urls'))
Template Authentification helpers
{% if request.user.is_authenticated %} Logged in as: {{ request.user.username }} {% endif %} Authorization: LoginRequiredMixin and login_required from django.contrib.auth.mixins import LoginRequiredMixin
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 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", {})
def logout_page(request): logout(request) return redirect("index") User Change password
user.set_password('raw password') Send Email
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
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
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)
post_save.connect(post_user_created_signal, sender=User) Seed 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 $ pip install django-dotenv add code to manage.py file 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 SECRET_KEY = 'your secret key' ALLOWED_HOST=127.0.0.1
In settings.py change security related settings to point to the .env file import os SECRET_KEY = os.environ.get('SECRET_KEY') ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS')