Form表单
概要
通常情况下,我们需要自自己手动在HTML页面面中,编写form标签和其内的其它元
素。但这费时费力力力,而而且有可能写得不不太恰当,数据验证也比比较麻烦。有鉴于此,Django在内部集成了一个表单模块,专门帮助我们快速处理理表单相关的内容。Django的表单模块给我们提供了了下面面三个主要功能:
- 准备和重构数据用于页面面渲染
- 为数据创建HTML表单元素
- 接收和处理理用用户从表单发送过来的数据
Form相关的对象包括
-
Widget:用用来渲染成HTML元素的部件,如:forms.Textarea对应HTML中的:
‘textarea’ 标签 -
Field:Form对象中的一个字段,如:EmailField表示email字段,如果这个字段不不是有效的Email地址格式,就会产生生错误。
-
Form:一系列列Field对象的集合,负责验证和显示HTML元素
-
Form Media:用用来渲染表单的CSS和JavaScript资源。
基本使用
1、使用
Form对象封装了一系列列Field和验证规则,Form类都必须直接或间接继承自django.forms.Form,定义Form有两种方方式:
-
直接继承Form
class XXXForm(forms.Form): pass
-
结合Model,继承django.forms.ModelForm
class XXX(models.Model): 字段 = models.CharField(max_length=30) 字段 = models.CharField(max_length=20) class XXXForm(ModelForm): class Meta: model = XXX field = ('字段', '字段') # 只显示model中指定的字段
2、示例代码
- models
class Shop(models.Model):
title = models.CharField('标题', max_length=30)
content = models.CharField('内容', max_length=20)
class Meta:
db_table = 'T_SHOP'
-
ModelForm
class ShopForm(ModelForm): class Meta: model = models.Shop fields = ('title', 'content')# 只显示model中指定的字段
-
views
from django.shortcuts import render # Create your views here. from .forms import ShopForm def add_shop(request): if request.method == "POST": form = ShopForm(request.POST) if form.is_valid(): # 所有验证都通过 # 处理理表单数据 title = form.cleaned_data['title'] print(title) # content = form.cleaned_data['content']# 保存数据 form.save() return render(request, 'shop/add_shop.html', {"shop_form": form}) else: form = ShopForm() return render(request, 'shop/add_shop.html', {"shop_form": form})
-
模板中使用
<form action="{% url 'add' %}" method="post"> {% csrf_token %} {{ shop_form }} <input type="submit" value="提交"/> </form>
常用的Field类
-
核心字段参数
参数名 说明 required 给字段添加必填属性,不不能空着,若要表示一个字段不是必需的,设置required=False label label参数用用来给字段添加‘人人类友好’的提示信息。如果没有设置这个参数,那么就用用字段的首首字母大写名字 label_suffix Django默认为上面面的label参数后面面加个冒号后缀,如果想自自定义,可以使用用label_suffix 参数 initial 为HTML页面面中表单元素定义初始值。也就是input元素的value参数的值 widget 指定渲染Widget时使⽤的widget类,也就是这个form字 widget 指定渲染Widget时使用用的widget类,也就是这个form字段在HTML⻚页面面中是显示为文文本输入入框?密码输入入框?单 help_text 该参数用用于设置字段的辅助描述文文本 error_messages 该参数允许你覆盖字段引发异常时的默认信息。 传递的是一个字典,其值为你想覆盖的错误信息 validators 指定一个列列表,其中包含了了为字段进行行行验证的函数 localize localize参数帮助实现表单数据输入入的本地化 disabled 设置有该属性的字段在前端页面中将显示为不可编辑状态 - 核心心字段
BooleanField | 默认的Widget:CheckboxInput 空值:Flase 规范:Python 的True 或 False。错误信息的键:required |
---|---|
FileField | |
ModelChoiceField | |
IntergerField | |
CharField | |
ChoiceField | |
DateField | |
DateTimeFiled | |
DecimalField | |
FloatField | |
EmailField | |
ImageField |
-
Form常用的属性和方法
cleaned_data(字典) 表单中通过验证的数据 form.cleaned_data.get(‘username’) changed_data 有变换的字段列表 form.change_data fields 表单中字段属性 is_bound 是否绑定 is_valid() 是否通过验证 errors 错误信息 has_changed() 表单数据是否已从初始状态数据更改 errors.as_json(escape_html)=Flase 返回json序列化后的错误信息字典 -
示例代码
- forms
# 用户表单 class UserForm(forms.Form): username = forms.CharField(label='用户名',min_length=3,max_length=30, error_messages={ 'required':'必填', 'min_length':'最少3个字符', 'max_length': '最多30字符', }) password_hash = forms.CharField(label='密码',validators=[check_password],min_length=6,max_length=128,widget=forms.PasswordInput(),error_messages={ 'required': '必填', 'min_length': '最少6个字符', 'max_length': '最多128字符', }) confirm_password = forms.CharField(label='确认密码',min_length=6,max_length=128,widget=forms.PasswordInput(),error_messages={ 'required': '必填', 'min_length': '最少6个字符', 'max_length': '最多128字符', }) sex = forms.ChoiceField(label='性别',choices=[(0,'女'),(1,'男'),(2,'保密')],initial=1,widget=forms.RadioSelect, required=False) address = forms.ChoiceField(label='家庭住址',choices=[(1,'北京'),(2,'上海'),(3,'广州'),(4,'深圳')]) email = forms.EmailField(label='邮箱',required=False,error_messages={ 'invalid':"邮箱格式无效" }) phone = forms.CharField(label='电话',min_length=11,required=False,error_messages={ 'min_length':'至少11位' }) regtime = forms.DateField(label='注册日期',required=False,error_messages={ 'invalid':'日期格式错误' }) usertype = forms.ChoiceField(label='用户类型',choices=[(1,'普通用户'),(2,'管理员')],required=False,initial=1)
-
views
def index(request): return HttpResponse("首页") def add(request): form = StudentForm() #空的表单,没有数据 if request.method == 'POST': form = StudentForm(request.POST) if form.is_valid(): #验证通过 print(form.cleaned_data) name = form.cleaned_data.get('name') sex = form.cleaned_data.get('sex') age = form.cleaned_data.get('age') #写入数据库 Stuent.objects.create(**form.cleaned_data) #验证成功跳转到首页 return redirect(reverse('index')) # return render(request,'add.html',context={'form':form}) # return render(request,'add1.html',context={'form':form}) # return render(request,'add2.html',context={'form':form}) return render(request,'add3.html',context={'form':form}) def register(request): form = UserForm() if request.method == 'POST': print(request.POST) form = UserForm(request.POST) if form.is_valid(): del form.cleaned_data['confirm_password'] value = form.cleaned_data['password_hash'] form.cleaned_data['password_hash'] = hashlib.sha1(value.encode('utf8')).hexdigest() print(form.cleaned_data) User.objects.create(**form.cleaned_data) return redirect(reverse('index')) return render(request,'register.html',context={'form':form}) def example(request): form = Example() if request.method == 'POST': form = Example(request.POST) if form.is_valid(): print(form.cleaned_data) return redirect(reverse('index')) return render(request,'example.html')
-
html
<form action="/add/" method="post"> {% csrf_token %} <div> <label for="{{ form.name.id_for_label }}">{{ form.name.label_tag }}</label> {{ form.name }} {{ form.name.errors }} </div> <div> <label for="{{ form.sex.id_for_label }}">{{ form.sex.label_tag }}</label> {{ form.sex }} {{ form.sex.errors }} </div> <div> <label for="{{ form.age.id_for_label }}">{{ form.age.label_tag }}</label> {{ form.age }} {{ form.age.errors }} </div> <input type="submit"> </form>
-
#register
<form action="/register/" method="post">
{% csrf_token %}
{# {% include 'renderform.html' %}#}
{# 渲染隐藏字段 #}
{% for hidefield in form.hidden_fields %}
{{ hidefield }}
{% endfor %}
{# 渲染可视字段 #}
{% for field in form.visible_fields %}
{% if field.html_name == 'sex' %}
{{ field.label_tag }}
{% for radio in form.sex %}
{{ radio.label_tag }}
{{ radio.tag }}
{{ radio.choice_label }}
{% endfor %}
{% else %}
<div>
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
</div>
{% endif %}
{% endfor %}
{# {% for radio in form.sex %}#}
{# {{ radio.label_tag }}#}
{# {{ radio.tag }}#}
{# {{ radio.choice_label }}#}
{# {% endfor %}#}
<input type="submit">
</form>
重写验证
- 注意
- 函数名必须为clean_字段名
- 必须有返回值
- 只能拿自己当前的字段值
示例代码
- 验证单个字段
def check_password(value):
if re.match(r'\d+$',value):
raise ValidationError("密码不能是纯数字")
-
类方法实现
class UserForm(forms.Form): def clean_phone(self): value = self.cleaned_data.get('phone') if not re.match(r"^1[35678]\d{9}$", value): raise ValidationError("手机号码不正确,请重新填写") else: return value
-
验证两个变单数据的一致
def clean(self): password1 = self.cleaned_data.get("password_hash") password2 = self.cleaned_data.get("confirm_password") print(password1,password2) if password1 != password2: raise ValidationError("两次密码不一致") else: return self.cleaned_data
**注意事项:**对于
标签中
{{ form.as_ul }} 将它们渲染在 - 标签中
注意,你必须自自己己提供 或- 元素。