Python Django 框架入门
目录
学习目标:掌握 Django 的核心概念,能够创建包含模型、视图、模板的完整 Web 应用,理解 MTV 架构模式。
1. Django 简介
Django 是 Python 最流行的全栈 Web 框架,遵循 " batteries included “(自带电池)哲学,提供从数据库到管理后台的完整解决方案。
1.1 核心特性
- ORM:对象关系映射,无需手写 SQL
- 管理后台:自动生成的 admin 界面
- 表单处理:数据验证和 HTML 表单生成
- 认证系统:用户认证、权限管理
- 模板引擎:强大的 HTML 模板系统
- 安全特性:CSRF 保护、SQL 注入防护等
1.2 MTV 架构
Django 使用 MTV(Model-Template-View)架构:
用户请求 → URLconf → View → Model(数据库)
↓
Template(HTML)
↓
响应用户| 组件 | 职责 | 类比 MVC |
|---|---|---|
| Model | 数据结构和业务逻辑 | Model |
| Template | 页面展示逻辑 | View |
| View | 处理请求,协调 Model 和 Template | Controller |
2. 快速开始
2.1 安装与创建项目
# 安装 Django
pip install django
# 创建项目
django-admin startproject mysite
# 目录结构
mysite/
manage.py ← 命令行工具
mysite/ ← 项目配置
__init__.py
settings.py ← 配置文件
urls.py ← URL 声明
asgi.py ← ASGI 入口
wsgi.py ← WSGI 入口
# 启动开发服务器
cd mysite
python manage.py runserver2.2 创建应用
# 创建应用
python manage.py startapp blog
# 应用目录结构
blog/
__init__.py
admin.py ← 后台配置
apps.py ← 应用配置
models.py ← 数据模型
views.py ← 视图函数
tests.py ← 测试
migrations/ ← 数据库迁移
__init__.py# mysite/settings.py - 注册应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # ← 添加自定义应用
]3. 模型(Model)
3.1 定义模型
# blog/models.py
from django.db import models
class Article(models.Model):
"""文章模型"""
title = models.CharField('标题', max_length=200)
content = models.TextField('内容')
author = models.CharField('作者', max_length=50)
created_at = models.DateTimeField('创建时间', auto_now_add=True)
updated_at = models.DateTimeField('更新时间', auto_now=True)
is_published = models.BooleanField('已发布', default=False)
class Meta:
db_table = 'articles'
ordering = ['-created_at']
verbose_name = '文章'
verbose_name_plural = '文章'
def __str__(self):
return self.title
class Comment(models.Model):
"""评论模型"""
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name='comments',
verbose_name='文章'
)
author = models.CharField('作者', max_length=50)
content = models.TextField('内容')
created_at = models.DateTimeField('创建时间', auto_now_add=True)
class Meta:
ordering = ['-created_at']3.2 常用字段类型
| 字段类型 | 说明 | 示例 |
|---|---|---|
| CharField | 短文本 | title = CharField(max_length=100) |
| TextField | 长文本 | content = TextField() |
| IntegerField | 整数 | age = IntegerField() |
| DecimalField | 精确小数 | price = DecimalField(max_digits=10, decimal_places=2) |
| DateTimeField | 日期时间 | created = DateTimeField(auto_now_add=True) |
| BooleanField | 布尔值 | is_active = BooleanField(default=True) |
| ForeignKey | 外键 | author = ForeignKey(User, on_delete=CASCADE) |
| ManyToManyField | 多对多 | tags = ManyToManyField(Tag) |
| OneToOneField | 一对一 | profile = OneToOneField(Profile) |
3.3 数据库迁移
# 生成迁移文件
python manage.py makemigrations
# 查看迁移 SQL
python manage.py sqlmigrate blog 0001
# 执行迁移
python manage.py migrate
# 创建超级用户
python manage.py createsuperuser3.4 ORM 操作
# shell 中练习: python manage.py shell
from blog.models import Article
# 创建
article = Article.objects.create(
title='Django 入门',
content='Django 是 Python 最好的 Web 框架...',
author='张三'
)
# 查询全部
articles = Article.objects.all()
# 条件查询
published = Article.objects.filter(is_published=True)
recent = Article.objects.filter(created_at__year=2024)
# 获取单个
article = Article.objects.get(id=1)
# 模糊查询
results = Article.objects.filter(title__contains='Django')
# 排序
articles = Article.objects.order_by('-created_at')
# 分页
page = Article.objects.all()[0:10] # 前 10 条
# 更新
article.title = '新标题'
article.save()
# 批量更新
Article.objects.filter(is_published=False).update(is_published=True)
# 删除
article.delete()
# 计数
count = Article.objects.count()
# 链式调用
recent_published = Article.objects.filter(
is_published=True
).order_by('-created_at')[:5]4. 视图(View)
4.1 函数视图
# blog/views.py
from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse
from .models import Article
def article_list(request):
"""文章列表"""
articles = Article.objects.filter(
is_published=True
).order_by('-created_at')
return render(request, 'blog/article_list.html', {
'articles': articles
})
def article_detail(request, article_id):
"""文章详情"""
article = get_object_or_404(Article, id=article_id)
return render(request, 'blog/article_detail.html', {
'article': article
})
def article_api(request):
"""文章 API"""
articles = Article.objects.filter(is_published=True)
data = [{
'id': a.id,
'title': a.title,
'author': a.author,
'created_at': a.created_at.isoformat()
} for a in articles]
return JsonResponse({'articles': data})4.2 类视图
from django.views import View
from django.views.generic import ListView, DetailView
from .models import Article
class ArticleListView(ListView):
"""文章列表视图(通用类视图)"""
model = Article
template_name = 'blog/article_list.html'
context_object_name = 'articles'
def get_queryset(self):
return Article.objects.filter(is_published=True)
class ArticleDetailView(DetailView):
"""文章详情视图"""
model = Article
template_name = 'blog/article_detail.html'
context_object_name = 'article'
pk_url_kwarg = 'article_id'
class ArticleAPIView(View):
"""API 类视图"""
def get(self, request):
articles = Article.objects.all()
data = [{'id': a.id, 'title': a.title} for a in articles]
return JsonResponse({'articles': data})
def post(self, request):
# 处理 POST 请求
return JsonResponse({'status': 'created'})5. URL 配置
# blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.article_list, name='article_list'),
path('article/<int:article_id>/', views.article_detail, name='article_detail'),
path('api/articles/', views.article_api, name='article_api'),
]
# mysite/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]6. 模板(Template)
6.1 模板语法
<!-- blog/templates/blog/article_list.html -->
<!DOCTYPE html>
<html>
<head>
<title>文章列表</title>
</head>
<body>
<h1>最新文章</h1>
<!-- 循环 -->
{% for article in articles %}
<article>
<h2>
<a href="{% url 'blog:article_detail' article.id %}">
{{ article.title }}
</a>
</h2>
<p>作者: {{ article.author }}</p>
<p>发布时间: {{ article.created_at|date:"Y-m-d H:i" }}</p>
<p>{{ article.content|truncatewords:30 }}</p>
</article>
{% empty %}
<p>暂无文章</p>
{% endfor %}
<!-- 条件判断 -->
{% if articles %}
<p>共 {{ articles|length }} 篇文章</p>
{% else %}
<p>文章列表为空</p>
{% endif %}
</body>
</html>6.2 模板继承
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}我的博客{% endblock %}</title>
</head>
<body>
<nav>
<a href="{% url 'blog:article_list' %}">首页</a>
</nav>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p> 2024 我的博客</p>
</footer>
</body>
</html>
<!-- blog/templates/blog/article_list.html -->
{% extends 'base.html' %}
{% block title %}文章列表 - 我的博客{% endblock %}
{% block content %}
<h1>文章列表</h1>
{% for article in articles %}
<article>
<h2>{{ article.title }}</h2>
<p>{{ article.content|truncatewords:50 }}</p>
</article>
{% endfor %}
{% endblock %}6.3 常用模板标签和过滤器
<!-- 变量 -->
{{ variable }}
{{ variable|default:"默认值" }}
<!-- 过滤器 -->
{{ name|upper }}
{{ content|truncatewords:50 }}
{{ date|date:"Y-m-d" }}
{{ items|length }}
{{ html_content|safe }}
<!-- 逻辑控制 -->
{% if user.is_authenticated %}
<p>欢迎, {{ user.username }}</p>
{% else %}
<p>请登录</p>
{% endif %}
<!-- 循环 -->
{% for item in items %}
{{ forloop.counter }}. {{ item }}
{% endfor %}
<!-- 包含模板 -->
{% include "partial/header.html" %}
<!-- 静态文件 -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">7. 管理后台
# blog/admin.py
from django.contrib import admin
from .models import Article, Comment
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
"""文章后台管理"""
list_display = ['title', 'author', 'is_published', 'created_at']
list_filter = ['is_published', 'created_at']
search_fields = ['title', 'content']
date_hierarchy = 'created_at'
ordering = ['-created_at']
fieldsets = (
('基本信息', {
'fields': ('title', 'author')
}),
('内容', {
'fields': ('content',)
}),
('状态', {
'fields': ('is_published',)
})
)
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ['article', 'author', 'created_at']
list_filter = ['created_at']8. 表单处理
# blog/forms.py
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
"""文章表单"""
class Meta:
model = Article
fields = ['title', 'content', 'author', 'is_published']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'rows': 10}),
}
# blog/views.py
from django.shortcuts import redirect
from .forms import ArticleForm
def article_create(request):
"""创建文章"""
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
article = form.save()
return redirect('blog:article_detail', article_id=article.id)
else:
form = ArticleForm()
return render(request, 'blog/article_form.html', {
'form': form
})<!-- blog/templates/blog/article_form.html -->
{% extends 'base.html' %}
{% block content %}
<h1>写文章</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">保存</button>
</form>
{% endblock %}9. 小结
| 组件 | 文件 | 作用 |
|---|---|---|
| Model | models.py | 定义数据结构 |
| View | views.py | 处理请求逻辑 |
| Template | templates/ | 渲染 HTML |
| URL | urls.py | 路由映射 |
| Admin | admin.py | 后台管理配置 |
| Form | forms.py | 数据验证和表单 |
10. 练习题
- 创建一个完整的 Django 博客应用,包含文章的增删改查功能。
- 为博客添加分类(Category)模型,实现文章分类功能。
- 使用 Django 的认证系统,实现用户注册和登录。
- 自定义管理后台,为文章列表添加批量发布功能。
下节预告:我们将学习 Flask,这个轻量灵活的微框架,理解其与 Django 不同的设计理念。