Django 框架基础使用
项目创建
用django-admin startproject
命令创建新项目,并进入该文件夹。
1 | django-admin startproject locallibrary |
django-admin工具会创建如下所示的文件夹结构:
1 | locallibrary/ |
locallibrary 项目的子文件夹是整个网站的进入点:
settings.py 包含所有的网站设置。这是可以注册所有创建的应用的地方,也是静态文件,数据库配置的地方,等等。
urls.py 定义了网站 url 到 view 的映射。虽然这里可以包含所有的 url,但是更常见的做法是把应用相关的 url 包含在相关应用中
wsgi.py 帮助 Django 应用和网络服务器间的通讯。你可以把这个当作模板。
manage.py脚本可以创建应用,和数据库通讯,启动开发用网络服务器。
创建catalog
1 | python3 manage.py startapp catalog |
绝大多数文件的命令和它们的目的有关(比如视图函数就是views.py,模型就是models.py,测试是tests.py,网站管理设置是admin.py,注册应用是apps.py)
一个migration文件夹,用来存储“migrations”——当你修改你的数据模型时,这个文件会自动升级你的数据库。
init.py — 一个空文件,Django/Python 会将这个文件作为Python 包并允许你在项目的其他部分使用它。
注册 catalog
打开项目设置文件 locallibrary/locallibrary/settings.py 找到 INSTALLED_APPS 列表里的定义。如下所示,在列表的最后添加新的一行。
1 | INSTALLED_APPS = [ |
配置数据库
settings.py 里面设置
1 | DATABASES = { |
链接 url 映射器
打开locallibrary/locallibrary/urls.py 并注意指导文字解释了一些使用 URL 映射器的方法。
1 | # URL 映射通过urlpatterns 变量管理,它是path() 函数的一个 Python 列表结构 |
数据库迁移
1 | python3 manage.py makemigrations |
ORM
在 Django 框架中,模型(Model) 是用于定义和管理应用程序的数据结构的核心组件。模型负责与数据库进行交互,定义数据的字段、行为以及数据之间的关系。通过使用 Django 的 ORM(对象关系映射),开发者可以方便地进行数据库操作,而无需编写复杂的 SQL 语句。
1. 模型的基本概念
Django 的模型是继承自 django.db.models.Model
的 Python 类。每个模型类对应数据库中的一张表,类的属性对应表中的字段。
1 | from django.db import models |
在这个示例中,Author
模型有两个字段:name
和 email
。Django 会自动为该模型创建一个名为 id
的主键字段,除非你手动指定其他主键。
2. 常用字段类型
Django 提供了丰富的字段类型来定义模型中的数据。以下是一些常用的字段类型:
CharField
:用于存储短文本,需要指定max_length
参数。TextField
:用于存储长文本。IntegerField
:用于存储整数。FloatField
:用于存储浮点数。BooleanField
:用于存储布尔值。DateField
和DateTimeField
:用于存储日期和日期时间。EmailField
:用于存储电子邮件地址。URLField
:用于存储 URL。1
2
3
4
5
6
7
class BlogPost(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
3. 模型之间的关系
Django 支持多种模型之间的关系,包括一对多、多对多和一对一关系。
一对多关系(ForeignKey)
一个 Author
可以有多篇 BlogPost
。
1 | class Author(models.Model): |
多对多关系(ManyToManyField)
一个 BlogPost
可以有多个 Tag
,一个 Tag
也可以属于多个 BlogPost
。
1 | class Tag(models.Model): |
一对一关系(OneToOneField)
一个 User
对应一个 Profile
。
1 | from django.contrib.auth.models import User |
4. 元数据(Meta)
Meta 类是 Django 模型中的一个内部类,用于定义模型的元数据。通过 Meta 类,开发者可以设置模型的排序方式、数据库表名、权限、抽象基类等属性。
常见的类型
permissions
:为模型定义自定义权限abstract
:指定该模型是否为抽象基类,抽象基类不会创建数据库表,但其字段会被子类继承app_label
:指定模型所属的应用标签,通常用于在模型定义不在其应用目录中时使用db_table
:指定数据库表中对应的表名verbose_name
和verbose_name_plural
:为模型指定单数和复数的可读名称,通常用于 Django 管理后台的显示unique_together
:指定多个字段组合在一起时必须唯一,确保数据库层面的唯一性约束1
2
3
4
5
6
7
8
9class BlogPost(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
class Meta:
# 定义模型的排序,并使用 - 前缀表示降序
ordering = ['-created_at']
# 为模型指定单数和复数的可读名称,通常用于 Django 管理后台的显示。
verbose_name = '博客文章'
verbose_name_plural = '博客文章集'
5. 自定义方法和属性
模型类可以定义自定义方法和属性,以便在模板或视图中使用。
1 | class BlogPost(models.Model): |
在模板中,可以通过 {{ blogpost.snippet }}
来调用该方法。
6. 模型的迁移
每当模型发生变化时,需要创建和应用迁移来同步数据库结构。
创建迁移
1 | python manage.py makemigrations |
应用迁移
1 | python manage.py migrate |
7. 使用模型
通过 Django 的 ORM,可以轻松地对模型进行增删改查操作。
创建对象
1 | author = Author.objects.create(name='张三', email='[email protected]') |
查询对象
1 | # 获取所有作者 |
更新对象
1 | author.email = '[email protected]' |
删除对象
1 | author.delete() |
8. 管理器(Manager)
每个模型都有一个默认的管理器 objects
,可以通过它进行数据库操作。你也可以自定义管理器来添加额外的查询方法。
实例
1 | class PublishedManager(models.Manager): |
现在,可以通过 BlogPost.published_posts.all()
获取所有已发布的博客文章。
9. 表单和模型
Django 提供了 ModelForm
,可以根据模型自动生成表单,简化表单处理。
1 | from django import forms |
10. Model Management
模型管理(Model Management) 是 Django 中用于创建、读取、更新和删除(CRUD)数据库记录的功能。通过 Django 的 ORM(对象关系映射),你可以轻松操作数据库,无需编写 SQL 语句。
1. 创建记录
通过实例化模型并调用 save()
方法:
1 | from myapp.models import MyModelName |
或者使用管理器的 create()
方法:
1 | new_record = MyModelName.objects.create(my_field_name="实例 #2") |
2. 查询记录
使用管理器的查询方法:
1 | # 获取所有记录 |
3. 更新记录
修改字段后调用 save()
:
1 | record = MyModelName.objects.get(id=1) |
或使用 update()
方法批量更新:
1 | MyModelName.objects.filter(my_field_name="旧名称").update(my_field_name="新名称") |
4. 删除记录
使用 delete()
方法:
1 | record = MyModelName.objects.get(id=1) |
批量删除:
1 | MyModelName.objects.filter(my_field_name="不需要的名称").delete() |
5. 批量操作与事务
批量创建:
1 | records = [ |
事务管理确保多个操作的原子性:
1 | from django.db import transaction |
超级用户
我们创建的应用里面有个admin.py
,初始内容是这样的:
1 | from django.contrib import admin |
我们导入模型之后进行注册
1 | from .models import Author, Genre, Book, BookInstance |
通过命令行创建超级用户:
1 | python3 manage.py createsuperuser |
ModelAdmin
在管理界面去改变一个模型的展示方式
1 |
|
控制哪些字段被显示和布局
在fields
属性列表只是要显示在表格上那些领域,如此才能。字段默认情况下垂直显示,但如果你进一步将它们分组在元组中(如上述“日期”字段中所示),则会水平显示。
1 | class AuthorAdmin(admin.ModelAdmin): |
视图管理
在 BookInstance
模型中,我们有相关的书是什么(即信息 name
、imprint
和 id
),并且当将可用(status
、due_back
)。我们可以通过将粗体文本添加到我们的BookInstanceAdmin
类中来将其添加到不同的部分。
1 |
|
内联编辑
1 | class BooksInstanceInline(admin.TabularInline): |
通用视图
- 定义:预定义的类视图,简化常见的Web开发任务(如显示列表、详情、创建、更新、删除)。
- 优势:
- 减少重复代码
- 提高开发效率
- 易于维护和扩展
常用通用视图类型
ListView
- 用途:显示对象列表
- 关键属性:
model
: 模型类template_name
: 模板路径context_object_name
: 上下文变量名paginate_by
: 每页显示数量
- 示例:
1
2
3
4
5
6
7
8from django.views.generic import ListView
from .models import Article
class ArticleListView(ListView):
model = Article
template_name = 'articles/article_list.html'
context_object_name = 'articles'
paginate_by = 10
DetailView
- 用途:显示单个对象详情
- 关键属性:
model
template_name
context_object_name
- 示例:
1
2
3
4
5
6
7from django.views.generic import DetailView
from .models import Article
class ArticleDetailView(DetailView):
model = Article
template_name = 'articles/article_detail.html'
context_object_name = 'article'
CreateView
- 用途:创建新对象,自动生成表单
- 关键属性:
model
form_class
或fields
template_name
success_url
- 示例:
1
2
3
4
5
6
7
8
9from django.views.generic import CreateView
from .models import Article
from .forms import ArticleForm
class ArticleCreateView(CreateView):
model = Article
form_class = ArticleForm
template_name = 'articles/article_form.html'
success_url = '/articles/'
UpdateView
- 用途:更新现有对象,自动生成表单
- 关键属性:与
CreateView
类似 - 示例:
1
2
3
4
5
6
7
8
9from django.views.generic import UpdateView
from .models import Article
from .forms import ArticleForm
class ArticleUpdateView(UpdateView):
model = Article
form_class = ArticleForm
template_name = 'articles/article_form.html'
success_url = '/articles/'
DeleteView
- 用途:删除对象,显示确认页面
- 关键属性:
model
template_name
success_url
- 示例:
1
2
3
4
5
6
7
8from django.views.generic import DeleteView
from .models import Article
from django.urls import reverse_lazy
class ArticleDeleteView(DeleteView):
model = Article
template_name = 'articles/article_confirm_delete.html'
success_url = reverse_lazy('article-list')
使用的基本步骤
- 定义模型
1
2
3
4
5
6
7
8
9from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title - 创建视图
- 继承相应的通用视图类
- 配置必要的属性
- 配置URL
1
2
3
4
5
6
7from django.urls import path
from .views import ArticleListView, ArticleDetailView
urlpatterns = [
path('', ArticleListView.as_view(), name='article-list'),
path('<int:pk>/', ArticleDetailView.as_view(), name='article-detail'),
] - 创建模板
- 根据
template_name
指定路径创建HTML文件 - 例如:
templates/articles/article_list.html
- 根据
自定义通用视图
- 覆盖类属性:如
template_name
、context_object_name
等 - 添加方法:
get_queryset()
: 自定义查询集form_valid()
: 自定义表单处理
- 使用 Mixins:添加额外功能(如权限控制)
示例:自定义查询集1
2
3
4
5
6
7
8
9
10from django.views.generic import ListView
from .models import Article
class PublishedArticleListView(ListView):
model = Article
template_name = 'articles/published_article_list.html'
context_object_name = 'articles'
def get_queryset(self):
return Article.objects.filter(status='published').order_by('-created_at')
示例项目概览
- 模型定义
1
2
3
4
5
6
7
8
9from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title - 视图创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from .models import Post
from django.urls import reverse_lazy
class PostListView(ListView):
model = Post
template_name = 'posts/post_list.html'
context_object_name = 'posts'
paginate_by = 5
class PostDetailView(DetailView):
model = Post
template_name = 'posts/post_detail.html'
context_object_name = 'post'
class PostCreateView(CreateView):
model = Post
fields = ['title', 'content']
template_name = 'posts/post_form.html'
success_url = reverse_lazy('post-list')
class PostUpdateView(UpdateView):
model = Post
fields = ['title', 'content']
template_name = 'posts/post_form.html'
success_url = reverse_lazy('post-list')
class PostDeleteView(DeleteView):
model = Post
template_name = 'posts/post_confirm_delete.html'
success_url = reverse_lazy('post-list') - URL配置
1
2
3
4
5
6
7
8
9
10from django.urls import path
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView
urlpatterns = [
path('', PostListView.as_view(), name='post-list'),
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('post/new/', PostCreateView.as_view(), name='post-create'),
path('post/<int:pk>/edit/', PostUpdateView.as_view(), name='post-update'),
path('post/<int:pk>/delete/', PostDeleteView.as_view(), name='post-delete'),
] - 模板创建
templates/posts/post_list.html
templates/posts/post_detail.html
templates/posts/post_form.html
templates/posts/post_confirm_delete.html
总结
- 通用视图:简化CRUD操作,减少代码量,提高开发效率。
- 使用步骤:
- 定义模型
- 创建通用视图
- 配置URL
- 创建模板
- 自定义:通过覆盖属性和方法,结合Mixins,满足特定需求。
Django 会话(Sessions)简明笔记
会话
- 定义:会话用于在多个请求之间存储和传递用户特定的数据,如登录状态、用户偏好等。
- 作用:保持用户状态,实现用户认证、购物车等功能。
工作原理
- 会话中间件:
SessionMiddleware
负责在每个请求和响应中添加会话支持。- 确保
request
对象具备session
属性。
- 会话存储:
- 默认使用数据库(
django.contrib.sessions.backends.db
)。 - 其他选项:
- 缓存:
django.contrib.sessions.backends.cache
- 文件系统:
django.contrib.sessions.backends.file
- 加密 cookie:
django.contrib.sessions.backends.signed_cookies
- 缓存数据库:
django.contrib.sessions.backends.cached_db
- 缓存:
- 默认使用数据库(
- 会话键:
- Django 生成一个唯一的会话键(session key)并存储在客户端的浏览器中,通常作为 cookie。
配置会话
- 启用会话中间件:
在settings.py
中确保MIDDLEWARE
包含'django.contrib.sessions.middleware.SessionMiddleware'
。1
2
3
4
5MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
# 其他中间件
] - 设置会话存储后端:
1
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 默认
- 会话过期设置:
- 全局过期:
1
SESSION_COOKIE_AGE = 1209600 # 两周,单位秒
- 浏览器关闭时过期:
1
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
- 全局过期:
- 安全设置:
1
2
3SESSION_COOKIE_SECURE = True # 仅通过 HTTPS 传输
SESSION_COOKIE_HTTPONLY = True # 防止 JavaScript 访问
SESSION_COOKIE_SAMESITE = 'Lax' # 防止跨站请求伪造
使用会话
- 设置会话数据:
1
2
3
4def set_session(request):
request.session['username'] = '张三'
request.session['is_logged_in'] = True
return HttpResponse("会话已设置") - 获取会话数据:
1
2
3
4def get_session(request):
username = request.session.get('username', '匿名用户')
is_logged_in = request.session.get('is_logged_in', False)
return HttpResponse(f"用户名: {username}, 登录状态: {is_logged_in}") - 删除会话数据:
1
2
3
4
5
6def delete_session(request):
try:
del request.session['username']
except KeyError:
pass
return HttpResponse("会话数据已删除") - 清除全部会话数据:
1
2
3def clear_session(request):
request.session.flush()
return HttpResponse("所有会话数据已清除")
会话示例
视图示例:
1 | from django.shortcuts import render, redirect |
会话安全性考虑
- 使用 HTTPS:确保
SESSION_COOKIE_SECURE = True
,防止会话 cookie 在不安全的连接上传输。 - 防止会话固定攻击:
- 登录后重新生成会话键:
1
2
3
4
5
6
7from django.contrib.auth import login
def login_user(request):
user = authenticate(request, username='张三', password='密码')
if user:
login(request, user) # 自动调用 session.flush()
return redirect('home')
- 登录后重新生成会话键:
- 限制会话寿命:通过设置
SESSION_COOKIE_AGE
和SESSION_EXPIRE_AT_BROWSER_CLOSE
控制会话过期时间。
常用会话方法
- **
request.session.save()
**:
手动保存会话数据。 - **
request.session.modified = True
**:
标记会话已修改,确保保存更改。 - **
request.session.clear_expired()
**:
清除过期的会话数据(通常由 Django 自动处理)。
高级配置
- 自定义会话存储:
可以创建自定义的会话引擎,满足特定需求。 - 信号:
Django 提供会话相关信号,如session_pre_save
、session_save
,用于在会话保存前后执行自定义操作。
总结
- 会话:在 Django 中用于在多个请求间存储用户数据,保持用户状态。
- 配置:通过中间件和
settings.py
进行配置,确保安全性和性能。 - 使用:通过
request.session
对象进行数据的设置、获取和删除。 - 安全:确保使用 HTTPS,配置安全的 cookie 设置,防止常见的会话攻击。
认证
- 定义:认证系统用于验证用户身份,确保用户是他们声称的身份。
- 作用:管理用户登录、登出、注册,以及权限控制,保护网站资源不被未授权访问。
Django 认证系统概述
- 内置功能:Django 提供了一个强大的内置认证系统,包括用户模型、认证视图、表单和装饰器。
- 主要组件:
- 用户模型(User Model):存储用户信息,如用户名、密码、电子邮件等。
- 认证视图:处理登录、登出和注册。
- 权限和组:管理用户权限和组织用户组。
- 装饰器和混合类:保护视图,限制访问权限。
配置认证系统
- 确保安装应用:
在settings.py
中,确保以下应用已添加到INSTALLED_APPS
:1
2
3
4
5
6
7
8
9INSTALLED_APPS = [
...
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
...
] - 中间件设置:
确保AuthenticationMiddleware
和SessionMiddleware
已启用:1
2
3
4
5
6
7
8
9MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
] - URL 配置:
在项目的urls.py
中包含认证视图:1
2
3
4
5
6
7from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
]
用户模型(User Model)
- 默认用户模型:Django 提供了一个默认的
User
模型,位于django.contrib.auth.models
。 - 自定义用户模型:
- 推荐:在项目开始时自定义用户模型,以满足特定需求。
- 方法:
1
2
3
4
5from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
bio = models.TextField(blank=True, null=True) - 配置:在
settings.py
中设置:1
AUTH_USER_MODEL = 'yourapp.CustomUser'
认证视图
Django 提供了一组通用视图来处理认证相关操作:
- 登录视图(LoginView):
- 路径:
/accounts/login/
- 模板:
registration/login.html
- 示例 URL 配置:
1
2
3
4
5
6from django.urls import path
from django.contrib.auth import views as auth_views
urlpatterns = [
path('login/', auth_views.LoginView.as_view(), name='login'),
]
- 路径:
- 登出视图(LogoutView):
- 路径:
/accounts/logout/
- 模板:
registration/logged_out.html
- 示例 URL 配置:
1
2
3urlpatterns = [
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]
- 路径:
- 密码重置视图:
- 路径:多个视图处理密码重置流程
- 模板:
registration/password_reset_form.html
等
用户注册
Django 不提供内置的注册视图,需要自行创建:
- 创建表单:
1
2
3
4
5
6
7
8
9from django import forms
from django.contrib.auth.models import User
class SignUpForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username', 'email', 'password'] - 创建视图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from .forms import SignUpForm
def signup_view(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.set_password(form.cleaned_data['password'])
user.save()
login(request, user)
return redirect('home')
else:
form = SignUpForm()
return render(request, 'registration/signup.html', {'form': form}) - 配置 URL:
1
2
3urlpatterns = [
path('signup/', signup_view, name='signup'),
] - 创建模板:
templates/registration/signup.html
保护视图
- 基于装饰器:
@login_required
:限制视图仅对登录用户可见。1
2
3
4
5from django.contrib.auth.decorators import login_required
def my_view(request):
...
- 基于类的视图混合类:
LoginRequiredMixin
:用于类视图。1
2
3
4
5from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class ProtectedView(LoginRequiredMixin, TemplateView):
template_name = 'protected.html'
权限和组
- 权限:
- 每个模型默认有
add
,change
,delete
,view
权限。 - 自定义权限:
1
2
3
4class Meta:
permissions = [
("can_publish", "Can publish articles"),
]
- 每个模型默认有
- 组:
- 用于将权限分组,便于管理多个用户的权限。
- 示例:
1
2
3
4
5from django.contrib.auth.models import Group, Permission
group = Group.objects.create(name='Editors')
permission = Permission.objects.get(codename='can_publish')
group.permissions.add(permission)
扩展用户功能
- 用户资料:
- 使用一对一关系扩展用户模型。
1
2
3
4
5
6from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(blank=True)
- 使用一对一关系扩展用户模型。
- 信号:
- 自动创建或保存用户资料。
1
2
3
4
5
6
7
8
9
10
11from django.db.models.signals import post_save
from django.dispatch import receiver
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
- 自动创建或保存用户资料。
安全性考虑
- 密码哈希:
- Django 使用强哈希算法(如 PBKDF2)存储密码,确保密码安全。
- CSRF 保护:
- 确保在表单中使用
{% csrf_token %}
以防止跨站请求伪造攻击。
- 确保在表单中使用
- 会话安全:
- 配置
SESSION_COOKIE_SECURE
,SESSION_COOKIE_HTTPONLY
,SESSION_COOKIE_SAMESITE
等设置。
- 配置
- 强密码策略:
- 配置
AUTH_PASSWORD_VALIDATORS
以强制执行密码复杂性要求。
- 配置
常用方法和属性
- 用户认证:
authenticate()
:验证用户名和密码。1
2
3
4
5from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
# 用户认证成功login()
:登录用户。1
2
3from django.contrib.auth import login
login(request, user)logout()
:登出用户。1
2
3from django.contrib.auth import logout
logout(request)
- 检查用户状态:
request.user.is_authenticated
:判断用户是否已登录。request.user.is_staff
:判断用户是否为工作人员。request.user.is_superuser
:判断用户是否为超级用户。
示例代码
登录视图示例:
1 | from django.contrib.auth import authenticate, login |
保护视图示例:
1 | from django.contrib.auth.decorators import login_required |
总结
- Django 认证系统:提供全面的用户认证和权限管理功能,简化用户管理和安全控制。
- 主要步骤:
- 配置认证系统(添加中间件和应用)。
- 使用内置视图或自定义视图处理登录、登出、注册。
- 保护视图,限制访问权限。
- 管理用户权限和组,确保资源安全。
- 扩展用户模型以满足项目需求。
- 安全性:遵循最佳实践,确保用户数据和会话的安全。
Django 表单(Forms)
- 定义:Django 表单用于处理用户输入的数据,简化表单的创建、验证和处理过程。
- 作用:
- 创建和渲染 HTML 表单
- 验证用户输入的数据
- 处理表单提交,保存数据到数据库
表单的类型
普通表单(Forms)
- 不直接关联数据库模型
- 适用于需要自定义字段或不需要保存到数据库的数据
模型表单(ModelForms)
- 直接基于 Django 模型创建表单
- 自动生成与模型字段对应的表单字段
- 简化数据保存到数据库的过程
创建表单
1. 普通表单
- 步骤:
- 在
forms.py
中定义表单类,继承自forms.Form
- 定义表单字段
- 在
- 示例:
1
2
3
4
5
6
7# myapp/forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100, label='你的名字')
email = forms.EmailField(label='电子邮件')
message = forms.CharField(widget=forms.Textarea, label='留言内容')
2. 模型表单
- 步骤:
- 在
forms.py
中定义表单类,继承自forms.ModelForm
- 指定关联的模型和要包含的字段
- 在
- 示例:
1
2
3
4
5
6
7
8# myapp/forms.py
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'content']
渲染表单到模板
- 步骤:
- 在视图中创建表单实例并传递给模板
- 在模板中渲染表单
- 视图示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# myapp/views.py
from django.shortcuts import render, redirect
from .forms import ContactForm
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# 处理表单数据
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = form.cleaned_data['message']
# 例如,发送邮件或保存到数据库
return redirect('success')
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form}) - 模板示例 (
templates/contact.html
):1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<head>
<title>联系表单</title>
</head>
<body>
<h1>联系我们</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">提交</button>
</form>
</body>
</html>
处理表单提交
- 验证数据:
- 使用
form.is_valid()
方法验证用户输入的数据 - 访问
form.cleaned_data
获取清洗后的数据
- 使用
- 示例:
1
2
3
4
5if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = form.cleaned_data['message']
# 处理数据,如保存或发送邮件
显示表单错误
- 模板中自动显示错误:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<form method="post">
{% csrf_token %}
{{ form.non_field_errors }}
<div>
{{ form.name.label_tag }}
{{ form.name }}
{{ form.name.errors }}
</div>
<div>
{{ form.email.label_tag }}
{{ form.email }}
{{ form.email.errors }}
</div>
<div>
{{ form.message.label_tag }}
{{ form.message }}
{{ form.message.errors }}
</div>
<button type="submit">提交</button>
</form>
使用 ModelForm 简化数据保存
视图示例:
1
2
3
4
5
6
7
8
9
10
11
12
13# myapp/views.py
from django.shortcuts import render, redirect
from .forms import ArticleForm
def create_article(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
form.save() # 自动保存到数据库
return redirect('article-list')
else:
form = ArticleForm()
return render(request, 'create_article.html', {'form': form})模板示例 (
templates/create_article.html
):1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<head>
<title>创建文章</title>
</head>
<body>
<h1>创建新文章</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">保存</button>
</form>
</body>
</html>
自定义表单字段和验证
- 添加自定义验证:
1
2
3
4
5
6
7
8
9
10
11
12
13# myapp/forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)
def clean_email(self):
email = self.cleaned_data.get('email')
if not email.endswith('@example.com'):
raise forms.ValidationError("只能使用 @example.com 的电子邮件地址。")
return email - 覆盖字段属性:
1
2
3
4
5
6
7
8class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'content']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control'}),
}
表单安全性
- 跨站请求伪造(CSRF)保护:
- 在模板中的
<form>
标签内添加{% csrf_token %}
模板标签 - 确保
CsrfViewMiddleware
已启用(默认启用)
- 在模板中的
- 示例:
1
2
3
4
5<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">提交</button>
</form>
高级功能
- 表单继承:
- 通过继承基础表单类,复用和扩展表单字段和逻辑
- 表单集(Formsets):
- 管理和处理多个相同类型的表单
- 嵌套表单:
- 组合多个表单,实现复杂的数据输入
示例项目概览
目标:创建一个允许用户提交博客文章的表单
模型定义:
1
2
3
4
5
6
7
8
9
10# myapp/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title表单创建:
1
2
3
4
5
6
7
8
9
10
11
12# myapp/forms.py
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control'}),
}视图创建:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# myapp/views.py
from django.shortcuts import render, redirect
from .forms import PostForm
from .models import Post
def create_post(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect('post-list')
else:
form = PostForm()
return render(request, 'create_post.html', {'form': form})
def post_list(request):
posts = Post.objects.all().order_by('-created_at')
return render(request, 'post_list.html', {'posts': posts})URL 配置:
1
2
3
4
5
6
7
8# myapp/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('posts/', views.post_list, name='post-list'),
path('posts/new/', views.create_post, name='create-post'),
]模板创建:
- 创建文章模板 (
templates/create_post.html
):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html>
<head>
<title>创建文章</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>创建新文章</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
</body>
</html> - 文章列表模板 (
templates/post_list.html
):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<html>
<head>
<title>文章列表</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>所有文章</h1>
<a href="{% url 'create-post' %}" class="btn btn-success mb-3">创建新文章</a>
<ul class="list-group">
{% for post in posts %}
<li class="list-group-item">
<h3>{{ post.title }}</h3>
<p>{{ post.content }}</p>
<small>创建于 {{ post.created_at }}</small>
</li>
{% empty %}
<li class="list-group-item">暂无文章。</li>
{% endfor %}
</ul>
</div>
</body>
</html>
- 创建文章模板 (
总结
- Django 表单:简化用户输入数据的创建、验证和处理过程。
- 类型:
- 普通表单:自定义字段,灵活使用
- 模型表单:基于模型,自动生成字段,便于数据保存
- 关键步骤:
- 创建表单类(普通或模型表单)
- 在视图中处理表单
- 在模板中渲染表单
- 验证和处理用户输入的数据
- 安全性:
- 使用 CSRF 保护
- 验证和清洗用户输入
- 高级功能:
- 表单继承、表单集、嵌套表单