Thiết Lập Dự Án
Tạo Dự Án & App
pip install django django-admin startproject mysite cd mysite python manage.py startapp blog
Các Lệnh Thường Dùng
runserverKhởi động dev server trên cổng 8000
makemigrationsTạo file migration từ thay đổi model
migrateÁp dụng migration vào database
createsuperuserTạo superuser cho admin
shellShell Python tương tác với Django
testChạy bộ test
Cấu Trúc Dự Án
manage.pyĐiểm vào CLI
settings.pyCấu hình dự án
urls.pyCấu hình URL gốc
wsgi.py / asgi.pyĐiểm vào server
apps/models.pyDatabase model
apps/views.pyXử lý request
Models
Định Nghĩa Model
from django.db import models class Post(models.Model): title = models.CharField(max_length=200) body = models.TextField() created = models.DateTimeField(auto_now_add=True) published = models.BooleanField(default=False)
Các Loại Field
CharField(max_length=N)Văn bản ngắn (bắt buộc max_length)
TextField()Văn bản dài (không giới hạn)
IntegerField()Giá trị số nguyên
FloatField()Số thực
BooleanField()True / False
DateTimeField()Ngày và giờ
EmailField()Email có xác thực
FileField(upload_to='')Upload file
Quan Hệ
author = models.ForeignKey( User, on_delete=models.CASCADE ) tags = models.ManyToManyField(Tag, blank=True) profile = models.OneToOneField(User, on_delete=models.CASCADE)
Meta & Methods
class Meta: ordering = ['-created'] verbose_name_plural = 'posts' def __str__(self): return self.title
Views
Function-Based View
from django.shortcuts import render, get_object_or_404 def post_list(request): posts = Post.objects.filter(published=True) return render(request, 'blog/list.html', {'posts': posts})
Class-Based Views
from django.views.generic import ListView, DetailView class PostListView(ListView): model = Post template_name = 'blog/list.html' context_object_name = 'posts' paginate_by = 10
CBV Thường Dùng
ListViewHiển thị danh sách object
DetailViewHiển thị một object
CreateViewForm tạo object
UpdateViewForm chỉnh sửa object
DeleteViewXác nhận và xóa object
TemplateViewRender template (không có model)
JSON Response
from django.http import JsonResponse def api_posts(request): data = list(Post.objects.values('id', 'title')) return JsonResponse(data, safe=False)
Templates
Cú Pháp Template
{{ variable }} {{ post.title|truncatewords:30 }} {% if user.is_authenticated %}

Xin chào, {{ user.username }}!

{% endif %}
Vòng Lặp & Điều Kiện
{% for post in posts %}

{{ post.title }}

{% if forloop.last %}
{% endif %} {% empty %}

Chưa có bài viết nào.

{% endfor %}
Kế Thừa Template
{# base.html #} {% block content %}{% endblock %} {# child.html #} {% extends "base.html" %} {% block content %}

Xin chào

{% endblock %}
Filter Thường Dùng
|date:"Y-m-d"Định dạng ngày
|default:"N/A"Dự phòng khi giá trị rỗng
|lengthĐếm phần tử trong list
|truncatewords:NGiới hạn N từ
|safeĐánh dấu HTML an toàn (không escape)
|slugifyChuỗi URL-safe chữ thường
URLs
URL Patterns
from django.urls import path, include urlpatterns = [ path('', views.index, name='index'), path('post//', views.detail, name='detail'), path('blog/', include('blog.urls')), ]
Path Converters
<int:pk>Số nguyên (vd: 42)
<str:slug>Chuỗi không có dấu gạch chéo
<slug:slug>Slug (chữ, số, gạch ngang)
<uuid:id>Định dạng UUID
<path:rest>Đường dẫn đầy đủ kể cả dấu gạch chéo
Reverse URLs
from django.urls import reverse url = reverse('detail', kwargs={'pk': 1}) # Trong template: {% url 'detail' pk=post.pk %}
Forms
Model Form
from django import forms class PostForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'body', 'published']
Xử Lý Form trong View
def create_post(request): form = PostForm(request.POST or None) if form.is_valid(): post = form.save(commit=False) post.author = request.user post.save() return redirect('detail', pk=post.pk) return render(request, 'blog/form.html', {'form': form})
Form trong Template
{% csrf_token %} {{ form.as_p }}
Validation
def clean_title(self): title = self.cleaned_data['title'] if len(title) < 5: raise forms.ValidationError("Tiêu đề quá ngắn.") return title
Admin
Đăng Ký Model
from django.contrib import admin from .models import Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ['title', 'author', 'created', 'published'] list_filter = ['published', 'created'] search_fields = ['title', 'body']
Tùy Chọn Admin
list_displayCột trong list view
list_filterTùy chọn lọc thanh bên
search_fieldsTrường có thể tìm kiếm
prepopulated_fieldsTự điền (vd: slug từ title)
readonly_fieldsKhông chỉnh sửa được trong admin
orderingThứ tự sắp xếp mặc định
ORM Queries
Query Cơ Bản
Post.objects.all() # tất cả bản ghi Post.objects.get(pk=1) # một bản ghi (lỗi nếu không tìm thấy) Post.objects.filter(published=True) # queryset Post.objects.exclude(draft=True) # loại trừ kết quả khớp Post.objects.count() # tổng số
Field Lookups
field__exactKhớp chính xác (mặc định)
field__icontainsChứa, không phân biệt hoa thường
field__gt / __ltLớn hơn / nhỏ hơn
field__gte / __lteLớn hơn hoặc bằng / nhỏ hơn hoặc bằng
field__in=[1,2,3]Giá trị nằm trong danh sách
field__isnull=TrueLà NULL
field__startswithBắt đầu bằng chuỗi
field__range=(a,b)Trong khoảng a đến b (bao gồm)
Kết Hợp & Tổng Hợp
from django.db.models import Q, Count, Avg Post.objects.filter( Q(title__icontains='django') | Q(body__icontains='django') ).order_by('-created')[:10] Post.objects.aggregate(avg_views=Avg('views'))
Tạo, Cập Nhật, Xóa
post = Post.objects.create(title='Mới', body='...') post.title = 'Đã cập nhật' post.save() Post.objects.filter(draft=True).update(published=False) post.delete()
Xác Thực
Đăng Nhập / Đăng Xuất
from django.contrib.auth import authenticate, login, logout user = authenticate(request, username='admin', password='pw') if user is not None: login(request, user)
Bảo Vệ Views
from django.contrib.auth.decorators import login_required @login_required def dashboard(request): return render(request, 'dashboard.html')
Auth URLs
# urls.py path('accounts/', include('django.contrib.auth.urls')) # Cung cấp: login, logout, password_change, password_reset
Auth trong Template
{% if user.is_authenticated %}

Xin chào, {{ user.username }}

Đăng xuất {% else %} Đăng nhập {% endif %}
Settings
Cài Đặt Quan Trọng
DEBUGTrue cho dev, False cho production
ALLOWED_HOSTSDanh sách hostname hợp lệ
SECRET_KEYKhóa ký mật mã (giữ bí mật)
DATABASESEngine DB, tên, host, thông tin xác thực
INSTALLED_APPSDanh sách app đã đăng ký
STATIC_URLURL prefix cho static file
MEDIA_URL / MEDIA_ROOTĐường dẫn file do người dùng tải lên
Cấu Hình Database
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydb', 'USER': 'dbuser', 'HOST': 'localhost', 'PORT': '5432', } }
Static Files
STATIC_URL = '/static/' STATICFILES_DIRS = [BASE_DIR / 'static'] # Trong template: {% load static %} #