pip install django
django-admin startproject mysite
cd mysite
python manage.py startapp blog
常用命令
runserver
在 8000 端口启动开发服务器
makemigrations
根据模型变更生成迁移文件
migrate
将迁移应用到数据库
createsuperuser
创建管理员超级用户
shell
带 Django 上下文的交互式 Python shell
test
运行测试套件
项目结构
manage.py
CLI 入口
settings.py
项目配置
urls.py
根 URL 配置
wsgi.py / asgi.py
服务器入口
apps/models.py
数据库模型
apps/views.py
请求处理器
模型
定义模型
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)
from django.views.generic import ListView, DetailView
class PostListView(ListView):
model = Post
template_name = 'blog/list.html'
context_object_name = 'posts'
paginate_by = 10
常用类视图
ListView
显示对象列表
DetailView
显示单个对象
CreateView
创建对象的表单
UpdateView
编辑对象的表单
DeleteView
确认并删除对象
TemplateView
渲染模板(无模型)
JSON 响应
from django.http import JsonResponse
def api_posts(request):
data = list(Post.objects.values('id', 'title'))
return JsonResponse(data, safe=False)
模板
模板语法
{{ variable }}
{{ post.title|truncatewords:30 }}
{% if user.is_authenticated %}
from django.urls import path, include
urlpatterns = [
path('', views.index, name='index'),
path('post//', views.detail, name='detail'),
path('blog/', include('blog.urls')),
]
路径转换器
<int:pk>
整数(如 42)
<str:slug>
不含斜杠的字符串
<slug:slug>
slug(字母、数字、连字符)
<uuid:id>
UUID 格式
<path:rest>
含斜杠的完整路径
反向解析 URL
from django.urls import reverse
url = reverse('detail', kwargs={'pk': 1})
# In templates: {% url 'detail' pk=post.pk %}
表单
ModelForm
from django import forms
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'body', 'published']
在视图中处理表单
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})
模板中的表单
验证
def clean_title(self):
title = self.cleaned_data['title']
if len(title) < 5:
raise forms.ValidationError("Title too short.")
return title
管理后台
注册模型
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']
Admin 选项
list_display
列表视图的列
list_filter
侧边栏过滤选项
search_fields
可搜索的字段
prepopulated_fields
自动填充(如从标题生成 slug)
readonly_fields
后台不可编辑的字段
ordering
默认排序
ORM 查询
基础查询
Post.objects.all() # all records
Post.objects.get(pk=1) # single (raises if missing)
Post.objects.filter(published=True) # queryset
Post.objects.exclude(draft=True) # exclude matches
Post.objects.count() # total count
字段查找
field__exact
精确匹配(默认)
field__icontains
不区分大小写包含
field__gt / __lt
大于 / 小于
field__gte / __lte
大于等于 / 小于等于
field__in=[1,2,3]
值在列表中
field__isnull=True
为 NULL
field__startswith
以字符串开头
field__range=(a,b)
在 a 和 b 之间(含)
链式与聚合
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'))
增删改
post = Post.objects.create(title='New', body='...')
post.title = 'Updated'
post.save()
Post.objects.filter(draft=True).update(published=False)
post.delete()
认证
登录 / 登出
from django.contrib.auth import authenticate, login, logout
user = authenticate(request, username='admin', password='pw')
if user is not None:
login(request, user)
保护视图
from django.contrib.auth.decorators import login_required
@login_required
def dashboard(request):
return render(request, 'dashboard.html')