form组件的主要功能如下:
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容
forms.py form组件一般单独放在一个py文件中,检验错误的信息放在 form_obj.errors
例如:{ "pwd":["密码太长,"], "email":["格式不对,"] , }
def clean_user(self): 这个叫做局部钩子 也可以引入models.py 进行校验
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render, HttpResponse from django.forms import Form, fields from django import forms from app01 import models from django.core.validators import RegexValidator from django.core.exceptions import ValidationError
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三", # 设置默认值
error_messages={ # 重写错误信息。
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
},
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
pwd = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'c1'},
render_value=True, ) # 校验值回不回填到HTML页面中
)
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3, # 设置默认值
widget=forms.widgets.RadioSelect # 设置生成的HTML标签的type类型
)
def clean_username(self):
username = self.cleaned_data.get("username")
if "666" in username:
raise ValidationError("光喊666是学不会!")
else:
return username
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.fields['hobby'].widget.choices = models.Hobby.objects.all().values_list('id', 'name')
# def __init__(self, *args, **kwargs): # 批量添加样式
# super(LoginForm, self).__init__(*args, **kwargs)
# for field in iter(self.fields):
# self.fields[field].widget.attrs.update({
# 'class': 'form-control'
# })
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class RegForm(forms.Form): user=forms.CharField(max_length=8,label="用户名", widget=widgets.TextInput(attrs={"class":"form-control"}) ) pwd=forms.CharField(min_length=4,label="密码", widget=widgets.PasswordInput(attrs={"class":"form-control"})) repeat_pwd=forms.CharField(min_length=4,label="确认密码", widget=widgets.PasswordInput(attrs={"class": "form-control"})) email=forms.EmailField(label="邮箱", widget=widgets.EmailInput(attrs={"class": "form-control"}) ) def clean_user(self): val=self.cleaned_data.get("user") # val=self.cleaned_data.get("pwd") ret=UserInfo.objects.filter(username=val) if not ret: return val else: raise ValidationError("该用户已存在") def clean(self): if self.cleaned_data.get("pwd")==self.cleaned_data.get("repeat_pwd"): return self.cleaned_data else: raise ValidationError("两次密码不一致!")
views.py
views.py (from app import forms from .models import UserInfo)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from app import forms from .models import UserInfo
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def register2(request): form_obj = RegisterForm() if request.method == "POST": form_obj = RegisterForm(request.POST) # 把POST请求的数据传到RegisterForm if form_obj.is_valid(): # 执行校验规则 # 校验通过 # 从校验好的数据中取需要的字段值 username = form_obj.cleaned_data.get("username") pwd = form_obj.cleaned_data.get("pwd") # 入库生成一条新纪录 models.UserInfo.objects.create(usernama=username,pwd=pwd) return HttpResponse("注册成功") # 实例化一个RegisterForm对象 return render(request, "register2.html", {"form_obj": form_obj})
ps: models.User.objects.create(**form_obj.cleaned_data)
cleaned_data里面没有csrftoken k v
html.html (3种渲染方式) ( 1、 {{ form_obj.as_p }} 会render初所有的,不建议使用)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>login</title> <style> .error { color: red; } </style> </head> <body> <form action="/login2/" method="post" novalidate> {% csrf_token %} <p> {{ form_obj.username.label }} {{ form_obj.username }} <span class="error">{{ form_obj.username.errors.0 }}</span> </p> <p> {{ form_obj.pwd.label }} {{ form_obj.pwd }} <span class="error">{{ form_obj.pwd.errors.0 }}</span> </p> <p> <input type="submit"> <span class="error">{{ error_msg }}</span> </p> </form> </body> </html>
上边的如果字段很多会麻烦,此时可以使用for循环来生成,但是为了给每个标签添加样式可以使用 widget =widgets............... 例如:widget =widgets.PasswordInput.....密码变加密
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form action="" novalidate > {# form组件#} {% for field in form %} <div class="form-group"> <label for="">{{ field.label }}</label> {{ field }} <span class="error pull-right"></span> </div> {% endfor %} {# 图片#} <div class="form-group"> <label for="avatar">头像<img class="avatar" src="/static/img/default.png" alt=""></label> <input type="file" id="avatar"> </div> {# 上传#} <input type="button" class="btn btn-default reg_btn pull-right" value="提交"><span class="error" style="color: red;margin-left: 20px"></span> </form> </div> </div> </div> {% csrf_token %}
forms.py其他情况
select
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class LoginForm(forms.Form): hobby = forms.fields.ChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=3, widget=forms.widgets.Select )
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class LoginForm(forms.Form): hobby = forms.fields.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=[1, 3], widget=forms.widgets.SelectMultiple )
checkbox
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class LoginForm(forms.Form): ... keep = forms.fields.ChoiceField( label="是否记住密码", initial="checked", widget=forms.widgets.CheckboxInput )
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class LoginForm(forms.Form): hobby = forms.fields.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple )
gender=forms.ChoiceField(choices=((1,"男"),(2,"女"),(3,"其他"))) publish=forms.ChoiceField(choices=Publish.objects.all().values_list("pk","title")) publish=forms.ModelChoiceField(queryset=Publish.objects.all()) authors=forms.ModelMultipleChoiceField(queryset=Author.objects.all())
爷类:chicefield
父类:modelchoicefield 单选的select
子类:multiolechoicefield 多选的select
关于choice的注意事项:
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.forms import Form from django.forms import widgets from django.forms import fields class MyForm(Form): user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), initial=2, widget=widgets.Select ) def __init__(self, *args, **kwargs): super(MyForm,self).__init__(*args, **kwargs) # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),) # 或 self.fields['user'].widget.choices = models.Classes.objects.all().values_list('id','caption')
init还可以批量添加样式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用户名", initial="张三", error_messages={ "required": "不能为空", "invalid": "格式错误", "min_length": "用户名最短8位" } ... def __init__(self, *args, **kwargs): super(LoginForm, self).__init__(*args, **kwargs) for field in iter(self.fields): self.fields[field].widget.attrs.update({ 'class': 'form-control' })