django系列8 --- 接收、处理、响应客户在界面的输入
前言
如果我们搭建的网站只发布内容且不接受客户的输入,那么就不需要表单。相反,如果你需要客户输入内容来做交互,那么就要使用表单来实现。
表单:django提供了一系列的工具和库帮助我们构建表单,目的是为了:接收、处理、响应客户在界面的输入。
一、html 表单
html代码中,<form>...</form>
括起来的内容就是表单,它允许我们输入文本、选择选项、操作对象,然后将这些内容发送给服务端,也就是我们写的django代码中进行进一步处理表单需要制定2点:数据的URL地址、数据请求使用的http方法
1.1 get 和 post 方法
处理表单时,只会用到get和post方法,任何一个更改数据库的请求都应该使用post,get只用于不会影响系统状态(不更改数据库数据)的请求 。
- django的登陆表单使用post方法传输数据,浏览器会封装表单数据,编码后传输给服务端。
- get方法提交数据时,会将数据捆绑到一个字符串中,类似URl:https://docs.djangoproject.com/search/?q=forms&release=1
二、django在表单中的角色
处理表单是一个很复杂的业务流程,正常流程是:准备好多种不同类型的大量数据以在表单中显示、呈现为 HTML、使用方便的界面进行编辑、返回到服务器、验证和清理,然后保存或传递 用于进一步处理。使用django的表单可以简化以上内容,提高开发效率:
- 准备并重组数据,以便下一步的渲染
- 为数据创建 HTML 表单
- 接收并处理客户端提交的表单及数据
三、django中的表单
django 表单的核心类是 Form 类,与 model 大致相同,描述了对象的逻辑结果、行为、在网页上呈现给我们的方式。Form 类描述了一张表单并决定了它如何运行和呈现在网页上,在浏览器中,表单字段以 HTML控件
的形式展现给我们,Form 类的每个字段类型都有与之匹配的控件类,
四、构建一张表单
4.1 form类
根目录下生成 forms.py 文件,django中表单内容:
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
每个form实例都有 is_valid()
方法,如果用户输入了内容,则返回True且将表单数据存储在属性cleaned_data
中,
4.2 视图
django网站的表单数据会交给后台的视图(views.py)来处理,为了处理表单数据,我们需要将它实例化到我们希望的URL中
# views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm
def get_name(request):
if request.method == 'POST':
# 如果这个表单是post请求,我们需要处理数据
form = NameForm(request.POST)
if form.is_valid(): # 检查界面是否传入表单数据
# 表单数据被存储在 form.cleaned_data 中
return HttpResponseRedirect('/thanks/') # 返回一个界面,输入该界面的URL
else:
# 如果是一个get请求,将创建一个空表单
form = NameForm()
return render(request, 'name.html', {'form': form})
4.3 模板
其中 {{ form }} 中的form是get_name()里的变量 form = NameForm(),把我们自定义的这个表单类传入到界面
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
表单API,参考:https://docs.djangoproject.com/zh-hans/4.0/ref/forms/api/#django.forms.Form
五、详解 django 表单的类
5.1 表单实例
表单分为2类,绑定和未绑定
- 未绑定数据的表单,当渲染给用户时,它是空或者包含默认值
- 绑定的表单拥有已提交的数据,因此可以用来判断数据是否合法,表单的
is_bound
属性用来判断是否具有绑定的数据
5.2 字段详解
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
如上表单,拥有的字段分别是: CharField 、 EmailField 和 BooleanField
(1)控件
每个表单字段都有一个控件类,控件类对应html表单控件,例如:<input type="text">
每个表单字段都有一个默认控件,比如charfield默认控件是 TextInput
,如果要指定控件如下:
from django import forms
class RunApiForm(forms.Form):
query_params = forms.CharField(label='查询参数', required=False, widget=forms.Textarea(attrs={'rows': 6,'cols': 80,}))
(2)字段数据
表单数据通过调用 is_valid()
验证成功,已验证的表单数据会被放到form.cleaned_data
字典中,数据已经被转换成 python 类型,但我们依然可以从 request.POST
中访问未验证的数据。最好还是使用校验后的数据,视图中处理表单数据:
# views.py
from django.core.mail import send_mail
from django import forms
from .forms import NameForm
from django.http import HttpResponseRedirect
from django.shortcuts import render
def get_name(request):
if request.method == 'POST':
form = NameForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['info@example.com']
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
else:
# 如果是一个get请求,将创建一个空表单
form = NameForm()
return render(request, 'name.html', {'form': form})
完成字段参考:https://docs.djangoproject.com/zh-hans/4.0/ref/forms/fields/
六、使用 django 表单模板
只需要将表单实例放到表单模板中即可,例如上面的 NameForm()
实例 form,传入表单模板 name.html
中,
else:
# 如果是一个get请求,将创建一个空表单
form = NameForm()
return render(request, 'name.html', {'form': form})
6.1 表单渲染选项
表单在界面是以什么形式展现,分为三种 表格、段落、列表呈现
{{ form.as_table }}
将它们呈现为包含在标签中的表格单元格{{ form.as_p }}
将它们包裹在<p>
标签中{{ form.as_ul }}
将它们包裹在<li>
标签中
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="Submit">
</form>
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="Submit">
</form>
6.2 手动渲染字段(ing)
(1)每个字段都可以用作为表单的一个属性,并被响应的渲染到django模板中,显示例如:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
(2)渲染表单的错误信息(ing)
6.3 遍历表单字段
(1)如果要给每个字段使用相同的html控件,则使用 {% for %}
依次循环处理:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
(2)遍历隐藏字段和可见字段(ing)
6.4 可复用的表单模板
你可以通过将表单的循环保存在一个独立的模板中,并覆盖表单的 template_name 属性来使用自定义模板渲染表单,从而减少重复。
# In your template:
{{ form }}
# In form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}