【django之form表单】
一、构建一个表单
假设你想在你的网站上创建一个简单的表单,以获得用户的名字。你需要类似这样的模板:
<form action="/your-name/" method="post"> <label for="your_name">Your name: </label> <input id="your_name" type="text" name="your_name"> <input type="submit" value="OK"> </form>
这是一个非常简单的表单。实际应用中,一个表单可能包含几十上百个字段,其中大部分需要预填充,而且我们预料到用户将来回编辑-提交几次才能完成操作。
我们可能需要在表单提交之前,在浏览器端作一些验证。我们可能想使用非常复杂的字段,以允许用户做类似从日历中挑选日期这样的事情,等等。
这个时候,让Django 来为我们完成大部分工作是很容易的。
Form表单的功能
- 自动生成HTML表单元素
- 检查表单数据的合法性
- 如果验证错误,重新显示表单(数据不会重置)
- 数据类型转换(字符类型的数据转换成相应的Python类型)
二、在Django 中构建一个表单
1、Form 类
创建form组件
from django import forms from django.forms import widgets from django.core.exceptions import NON_FIELD_ERRORS, ValidationError class LoginForm(forms.Form): user=forms.CharField(label="用户名",min_length=3,max_length=8, widget=widgets.TextInput(attrs={"class": "form-control"}), error_messages={"min_length":"太短","required":"必填"}) pwd=forms.CharField(label="密码",min_length=5, widget=widgets.PasswordInput(attrs={"class":"form-control"}), error_messages={"min_length":"太短", "required": "必填"} )
2、views.py
如果访问视图的是一个GET
请求,它将创建一个空的表单实例并将它放置到要渲染的模板的上下文中。这是我们在第一个访问该URL 时预期发生的情况。
如果表单的提交使用POST
请求,那么视图将再次创建一个表单实例并使用请求中的数据填充它:form = NameForm(request.POST)
。这叫做”绑定数据至表单“(它现在是一个绑定的表单)。
我们调用表单的is_valid()
方法;如果它不为True
,我们将带着这个表单返回到模板。这时表单不再为空(未绑定),所以HTML 表单将用之前提交的数据填充,然后可以根据要求编辑并改正它。
如果is_valid()
为True
,我们将能够在cleaned_data
属性中找到所有合法的表单数据。在发送HTTP 重定向给浏览器告诉它下一步的去向之前,我们可以用这个数据来更新数据库或者做其它处理。
-
if GET请求
if GET请求: login_form=LoginForm() return render(request,"login_form.html",locals()) 渲染方式: (1) login_form.as_p (2) 推荐 <form action="" method="post" novalidate> {% csrf_token %} <div class="form-group"> <label for="">{{ login_form.user.label }}</label> {{ login_form.user }} <span>{{ login_form.errors.user.0 }}</span> </div> <div class="form-group"> <label for="">{{ login_form.pwd.label }}</label> {{ login_form.pwd }} <span>{{ login_form.errors.pwd.0 }}</span> </div> <input type="submit"> </form>
-
if POST 请求
if POST 请求: login_form=LoginForm(request.POST) if login_form.is_valid(): # 所有字段验证成功 # 所有请求数据:login_form.cleaned_data else: #login_form.errors # 字典:{"user":["","",]} #login_form.errors.get("user") # 列表:["",""] return render(request, "login_form.html", locals()) 渲染: <form action="" method="post" novalidate> {% csrf_token %} <div class="form-group"> <label for="">{{ login_form.user.label }}</label> {{ login_form.user }} <span>{{ login_form.errors.user.0 }}</span> </div> <div class="form-group"> <label for="">{{ login_form.pwd.label }}</label> {{ login_form.pwd }} <span>{{ login_form.errors.pwd.0 }}</span> </div> <input type="submit"> </form>
-
is_valid()
Form
的实例具有一个is_valid()
方法,它为所有的字段运行验证的程序。当调用这个方法时,如果所有的字段都包含合法的数据,它将:
- 返回
True
- 将表单的数据放到
cleaned_data
属性中。
is_valid: self.errors={} self.cleaned_data={} for name ,field in self.fields.items(): if field(数据): self.cleaned_data[name]="数据" else: self.errors[name]="错误信息"
钩子函数
def clean_user(self): val=self.cleaned_data.get("user") import re # if not UserInfo.objects.filter(username=val): # return val # else: # raise ValidationError("") if not val.isdigit(): return val else: raise ValidationError("用户名不能是纯数字!") def clean_pwd(self): val=self.cleaned_data.get("pwd") if val.startswith("yuan"): return val else: raise ValidationError("没有yuan开头")
代码
from django.shortcuts import render,HttpResponse # Create your views here. from django import forms from django.forms import widgets from django.core.exceptions import NON_FIELD_ERRORS, ValidationError class LoginForm(forms.Form): user=forms.CharField(label="用户名",min_length=3,max_length=8, widget=widgets.TextInput(attrs={"class": "form-control"}), error_messages={"min_length":"太短","required":"必填"}) pwd=forms.CharField(label="密码",min_length=5, widget=widgets.PasswordInput(attrs={"class":"form-control"}), error_messages={"min_length":"太短", "required": "必填"} ) def clean_user(self): val=self.cleaned_data.get("user") import re # if not UserInfo.objects.filter(username=val): # return val # else: # raise ValidationError("") if not val.isdigit(): return val else: raise ValidationError("用户名不能是纯数字!") def clean_pwd(self): val=self.cleaned_data.get("pwd") if val.startswith("yuan"): return val else: raise ValidationError("没有yuan开头") # email=forms.EmailField() # age=forms.IntegerField() def login(request): if request.method=="POST": login_form=LoginForm(request.POST) if login_form.is_valid(): print(login_form.cleaned_data) # {"user":"","pwd":123} return HttpResponse("OK") else: # print(login_form.cleaned_data)# {"pwd":123456} # print(type(login_form.errors)) # {"user":["","",]} # print(type(login_form.errors.get("user"))) # {"user":"....."} return render(request, "login_form.html", locals()) login_form=LoginForm() return render(request,"login_form.html",locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> {#<form action="" method="post" novalidate>#} {# {% csrf_token %}#} {# {{ login_form.as_p }}#} {# <input type="submit">#} {#</form>#} <hr> <div class="container"> <div class="row"> <div class="col-md-5"> <form action="" method="post" novalidate> {% csrf_token %} <div class="form-group"> <label for="">{{ login_form.user.label }}</label> {{ login_form.user }} <span>{{ login_form.errors.user.0 }}</span> </div> <div class="form-group"> <label for="">{{ login_form.pwd.label }}</label> {{ login_form.pwd }} <span>{{ login_form.errors.pwd.0 }}</span> </div> <input type="submit"> </form> </div> </div> </div> </body> </html>