参考:Django搭建个人博客:使用Form表单类发表新文章
Forms表单类
处理表单是一件挺复杂的事情。Django的表单功能可以简化大部分工作,并且也能比大多数程序员自己编写代码去实现来的更安全。
Django表单系统的核心组件是 Form 类。
类似于模型类的字段映射到数据库字段的方式,表单类的字段会映射到HTML表单的<input>元素。 ModelForm 通过 Form 映射模型类的字段到HTML表单的 <input> 元素,Django admin就基于此。
构建一张表单
article/中创建forms.py文件,并写入如下代码:
article/forms.py
# 引入表单类
from django import forms
# 引入文章模型
from .models import ArticlePost
# 写文章的表单类
class ArticlePostForm(forms.ModelForm):
class Meta:
# 指明数据模型来源
model = ArticlePost
# 定义表单包含的字段
fields = ('title', 'body')
- 代码中
ArticlePostForm类继承了Django的表单类forms.ModelForm,并在类中定义了内部类class Meta中指明了数据模型的来源,以及表单中应该包含数据模型的哪些字段。- 在
ArticlePost模型中,created和updated字段为自动生成,不需要填入;author字段暂时固定为id=1的管理员用户,也不用填入;剩下的title和body就是表单需要填入的内容了。
接下来,改写article/views.py,添加一个视图函数以处理写文章的请求:
article/views.py
...
# 引入redirect重定向模块
from django.shortcuts import render, redirect
# 引入HttpResponse
from django.http import HttpResponse
# 引入刚才定义的ArticlePostForm表单类
from .forms import ArticlePostForm
# 引入User模型
from django.contrib.auth.models import User
...
#写文章的视图
def article_create(request):
#判断用户是否提交数据
if request.method == "POST" :
#将提交的数据赋值到表单实例中
article_post_form = ArticlePostForm (request.POST)
#判断提交的数据是否满足模型的要求
if article_post_form.is_valid():
#保存数据,但暂时不提交到数据库中
new_article = article_post_form.save(commit=False)
#指定数据库中 id = 1 的用户为作者
new_article.author = User.objects.get(pk=1)
#将新文章保存到数据库中
new_article.save()
#完成后返回到文章列表
return redirect("article:article_list")
#如果数据不合法,返回错误信息
else:
return HttpResponse("表单内容有误,清重新填写")
#如果用户请求获取数据
else:
#创建表单类实例
article_post_form = ArticlePostForm()
#赋值上下文
context = {'article_post_form' : article_post_form }
#返回模板
return render(request,'article/create.html',context)
当视图函数接收到一个客户端的request请求时,首先根据request.method判断用户是要提交数据(POST)、还是要获取数据(GET):
- 如果用户是提交数据,将POST给服务器的表单数据赋于
article_post_form实例。
- 然后使用Django内置的方法
.is_valid()判断提交的数据是否满足模型的要求。
- 如果满足要求,保存表单中的数据(但是
commit=False暂时不提交到数据库,因为author还未指定),并指定author为id=1的管理员用户。然后提交到数据库,并通过redirect返回文章列表。redirect可通过url地址的名字,反向解析到对应的url。- 如果不满足要求,则返回一个字符串 "表单内容有误,请重新填写" ,告诉用户出现了什么问题。
- 如果用户是获取数据,则返回一个空的表单类对象,提供给用户填写。
写好视图之后,就需要写模板文件了。在templates/article/中创建create.html:
templates/article/create.html
<!--extends表明此页面继承自base.html文件-->
{% extends 'base.html' %}
<!--写入 base 中定义的title-->
{% block title %}写文章{% endblock title %}
<!--写入 base 中定义的content文件-->
{% block content %}
<!--写文章表单-->
<div class="container">
<div class="row">
<div class="col-12">
<br />
<!--提交文章的表单-->
<form method="post" action=".">
<!-- Django中POST 必须有 csrf_token -->
{% csrf_token %}
<!-- 文章标题 -->
<div class="form-group">
<!-- 标签 -->
<label for="title">文章标题</label>
<!-- 文本框 -->
<input
type="text"
class="form-control"
id="title"
name="title"
/>
</div>
<!-- 文章正文 -->
<div class="form-group">
<label for="body">文章正文</label>
<!-- 文本区域 -->
<textarea
type="text"
class="form-control"
id="body"
name="body"
rows="12"
></textarea>
</div>
<!-- 提交按钮 -->
<button type="submit" class="btn btn-primary">完成</button>
</form>
</div>
</div>
</div>
{% endblock content %}
<form>..</form>标签中的内容就是需要提交的表单。method="post"指定了表单提交的方式为POST(与视图函数中的request.method相联系);action="."指定了表单提交的地址为默认的当前url。- 关于
{% csrf_token %},它是Django中一个与网络安全相关的中间件验证。目前我们暂时不去深究它的实现,只需要知道表单中必须包含它就可以了,否则将会得到一个403错误。<input>和<textarea>标签中的name=''属性指定了当前文本框提交的数据的名称,它必须与表单类中的字段名称对应,否则服务器无法将字段和数据正确的对应起来。
或者:
{% csrf_token %}
{% for f in form %}
<div class="col-12 my-2">{{f.label_tag}}</div>
<div class="col-12 my-2">{{f}}</div>
{% endfor %}
最后,在article/urls.py中增加一个写文章的url地址:
article/urls.py
urlpatterns = [
...
# 写文章
path('article-create/', views.article_create, name='article_create'),
]
优化写文章入口
与之前类似,我们需要在导航栏中设置一个写文章的入口,优化使用体验。
将下列代码加入到templates/header.html中:
<li class="nav-item">
<a class="nav-link" href="{% url 'article:article_create' %}">写文章</a>
</li>
保存修改并运行服务器,地址栏中输入:http://127.0.0.1:8000/article/article-create/,看到如下界
面: