Form组件------注册
form组件的主要功能如下:
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容
forms.py form组件一般单独放在一个py文件中,检验错误的信息放在 form_obj.errors
例如:{ "pwd":["密码太长,"], "email":["格式不对,"] , }
def clean_user(self): 这个叫做局部钩子 也可以引入models.py 进行校验
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
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'
# })
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)
from app import forms from .models import UserInfo
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初所有的,不建议使用)
<!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.....密码变加密
<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
class LoginForm(forms.Form): hobby = forms.fields.ChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=3, widget=forms.widgets.Select )
class LoginForm(forms.Form): hobby = forms.fields.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=[1, 3], widget=forms.widgets.SelectMultiple )
checkbox
class LoginForm(forms.Form): ... keep = forms.fields.ChoiceField( label="是否记住密码", initial="checked", widget=forms.widgets.CheckboxInput )
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的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。
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还可以批量添加样式
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' })