一 创建一个form组件
导入forms模块组件:from django import forms
创建组件:创建一个类继承者forms.Form这个类
类型:
CharField:字符串类型,min_length:字符长度不能小于多少;max_length:字符的长度不能大于多少,error_messages:可以根据保存信息显示对应的中文报错,required:该字段不能够为空,widget:对input标签操作。
IntegerField:整数类型,invalid:格式错误
MultiplechioceField:设置字段为多选框(单选框)。initial=[数字,]:初始个数。choices=((value,数据),(value,数据)):为多选框(单选框赋值)。widgets.CheckboxSelectMultiple:设置为复选框
其他类型:
Field required=True, 是否允许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否可以编辑 label_suffix=None Label内容后缀 CharField(Field) max_length=None, 最大长度 min_length=None, 最小长度 strip=True 是否移除用户输入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 总长度 decimal_places=None, 小数位长度 BaseTemporalField(Field) input_formats=None 时间格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 时间间隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定制正则表达式 max_length=None, 最大长度 min_length=None, 最小长度 error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否允许空文件 ImageField(FileField) ... 注:需要PIL模块,pip3 install Pillow 以上两个字典使用时,需要注意两点: - form表单中 enctype="multipart/form-data" - view函数中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默认select插件 label=None, Label内容 initial=None, 初始值 help_text='', 帮助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查询数据库中的数据 empty_label="---------", # 默认空显示内容 to_field_name=None, # HTML中value的值对应的字段 limit_choices_to=None # ModelForm中对queryset二次筛选 ModelMultipleChoiceField(ModelChoiceField) ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 对选中的值进行一次转换 empty_value= '' 空值的默认值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 对选中的每一个值进行一次转换 empty_value= '' 空值的默认值 ComboField(Field) fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中 path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 允许文件 allow_folders=False, 允许文件夹 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 SlugField(CharField) 数字,字母,下划线,减号(连字符) ... UUIDField(CharField) uuid类型 ...
根据不同要求为表单加上不同的属性值:导入from django.forms impost widgets
widgets.PasswoedInput:加上密文的属性值,addrs:为指定的标签加上属性。
widgets.TextInput:文本信息
widgets.Select:下拉菜单,choices:为option出入值和value属性值
钩子clean:首先导入异常:from django.core.exceptions import ValidationError。
局部钩子:clean_字段名,就是使用clean_加上一个字段名。用于字段校验
raise calidationsError:抛出错误信息
cleaned_data:如果符合条件,数据就会存放在这里面,可以使用get获取是一个有序的字典格式,从上往下依次判断添加。
for name, field in self.fields.items(): try: value = field.clean(value) self.cleaned_data[name] = value if hasattr(self, 'clean_%s' % name): value = getattr(self, 'clean_%s' % name)() self.cleaned_data[name] = value except ValidationError as e: self.add_error(name, e)
全局钩子:clean,直接在这个函数里面定义功能,可以用于多个字段的操作和比较,直接可以获取cleaned_data里面的数据。
__all__:全局抛出来的错误存放在这个里面的。
self.clean() # def self.clean():return self.cleaned_data return not self.errors # True或者False
from django import forms from django.forms import widgets from django.core.exceptions import ValidationError class LoginForm(forms.Form): user=forms.CharField(min_length=5,max_length=12, error_messages={ "required":"该字段不能为空", "min_length":"该字段的长度不能小于5", "max_length":"该字段的长度不能大于12"}, widget=widgets.TextInput(attrs={"class":"form-control"}) ) pwd=forms.CharField( error_messages={ "invalid": "必须是数字" }, widget=widgets.PasswordInput(attrs={"class":"form-control",}) ) gender=forms.CharField( widget=widgets.Select(choices=((1,'男'),(0,'女'),)) ) usersss = forms.MultipleChoiceField( initial=[2, ], choices=((1, '上海'), (2, '北京'),), widget=widgets.CheckboxSelectMultiple ) def clean_user(self): print("============",self.cleaned_data.get("pwd")) # ============ None if not self.cleaned_data.get("user").isdigit(): return self.cleaned_data.get("user") else: raise ValidationError("该字段不能是纯数字") def clean_pwd(self): print("-----------------",self.cleaned_data.get("user")) import re val=self.cleaned_data.get("pwd") ret=re.findall("^d{6}yuan$",val) if ret: return val else: raise ValidationError("密码不符合设定要求") def clean(self): if self.cleaned_data.get("user") and self.cleaned_data.get("pwd"): if self.cleaned_data.get("user") != self.cleaned_data.get("pwd"): return self.cleaned_data else: raise ValidationError("用户名与密码不能一致!") return self.cleaned_data
django内置插件:
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
常用选择插件:
# 单radio,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 单radio,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 单select,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 单select,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多选select,值为列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 单checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多选checkbox,值为列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )
二 实例form对象
实例化时: self.fields={ "username":"字段规则对象", "password":"字段规则对象", }
LoginForm:form自建实例的对象存放的地点,request.POST:将数据传递给对应的字段,绑定数据的表单实例
is_valid:校验,将检验是否符合要求,返回的是一个布尔值
cleaned_data:检验正确数据就存放在这里面,是以字典的格式存放的,出数据。
errors:检验没有通过或错误的信息存放在这个里面,是以字典的格式存放的。errors.get获取里面的某些数据。
from django.shortcuts import render,HttpResponse # Create your views here. from django import forms from .models import * from django.forms import widgets from .forms import * def login(request): if request.method=="POST": #print(request.POST) #<QueryDict: {'csrfmiddlewaretoken': ['0xrifjX7jplIZwngbrRjpHPXw6kyDVa2Erca0sGYfjH9UuDfHzNUdMzlh7EH2v44'], 'user': ['asdas'], 'pwd': ['12321321']}> login_form=LoginForm(request.POST) # 将数据传给对应字段 绑定数据的表单实例 ''' # self.cleaned_data={"pwd":"12312412"} # self.errors={"user":"yuan",} ''' if login_form.is_valid(): print("通过验证") print(login_form.cleaned_data) print("use:",login_form.cleaned_data.get("user")) print(login_form.errors) ############### # user=login_form.cleaned_data.get("user") # pwd=login_form.cleaned_data.get("pwd") # UserInfo.objects.filter(username=user,password=pwd) # UserInfo.objects.filter(**login_form.cleaned_data) return HttpResponse("OK") else: # print("验证失败") # print(login_form.cleaned_data) # {'pwd': 77777} # print(login_form.errors) # ################## login_form.errors是什么类型 # print(type(login_form.errors))# <class 'django.forms.utils.ErrorDict'> # ###################获取login_form.errors的某个键的值 # print(login_form.errors.get("user")) # print(type(login_form.errors.get("pwd")))# <class 'django.forms.utils.ErrorList'> # # #login_form.errors={"user":["小于5位","不是数字"],"pwd":["",""]} errors=login_form.errors# {"user":["该字段不能是纯数字",],"pwd":["",""]} print("errors-->",errors) error_all=errors.get("__all__") return render(request, "login.html", {"login_form": login_form,"errors":errors,"error_all":error_all}) #### get请求 login_form=LoginForm() # form组件的实例对象 未绑定表单实例 return render(request,"login.html",{"login_form":login_form})
三 html文件渲染
模板导入input标签:直接用对象.字段取出内容 {{ 对象.字段}}
模板导入错误信息:直接使用srrors.字段名.0取出数据{{ srrors.字段名.0 }}
form组件只能够直接渲染input标签,form标签还是需要自己写的。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 新 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css"> <style> .container{ margin-top: 100px; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6"> <form action="/login/" method="post"> {% csrf_token %} <div class="form-group"> <label for="user">user</label> {{ login_form.user }} <span>{{ errors.user.0 }}</span> </div> <div class="form-group"> <label for="pwd">pwd</label> {{ login_form.pwd }} <span>{{ errors.pwd.0 }}</span> </div> <div class="form-group"> <label for="gender">gender</label> {{ login_form.gender }}<span>{{ error_all.0 }}</span> </div> <p>{{ login_form.usersss }}</p> <button type="submit" class="btn btn-default">Submit</button> </form> <hr> {# <form action="">#} {# {{ login_form.as_p }}#} {# </form>#} </div> </div> </div> </body> </html>
四 其他渲染对象
对于<label>/<input>
对,还有几个输出选项:
{{ form.as_table }}
以表格的形式将它们渲染在<tr>
标签中{{ form.as_p }}
将它们渲染在<p>
标签中{{ form.as_ul }}
将它们渲染在<li>
标签中
注意,你必须自己提供<table>
或<ul>
元素。
{{ form.as_p }}
结果如下:
<form action=""> <p> <label for="id_username">Username:</label> <input id="id_username" maxlength="100" name="username" type="text" required=""> </p> <p> <label for="id_password">Password:</label> <input id="id_password" maxlength="100" name="password" placeholder="password" type="password" required=""> </p> <p> <label for="id_telephone">Telephone:</label> <input id="id_telephone" name="telephone" type="number" required=""> </p> <p> <label for="id_email">Email:</label> <input id="id_email" name="email" type="email" required=""> </p> <p> <label for="id_is_married">Is married:</label> <input id="id_is_married" name="is_married" type="checkbox"> </p> <input type="submit" value="注册"> </form>
这种渲染有了限制,不能个自定义的渲染,而是将所有的字段全部渲染过去。
手动渲染:我们没有必要非要让Django 来分拆表单的字段;如果我们喜欢,我们可以手工来做每个字段都是表单的一个属性,可以使用{{ form.name_of_field }}
访问,并将在Django 模板中正确地渲染
<div class="fieldWrapper"> {{ form.Username.errors }} {{ form.Username.label_tag }} {{ form.Username }} </div>
五 表单渲染的错误信息
registerForm=RegisterForm(request.POST) print(type(registerForm.errors)) #<class 'django.forms.utils.ErrorDict'> print(type(registerForm.errors["username"])) #<class 'django.forms.utils.ErrorList'>
使用{{ form.name_of_field.errors }} 显示表单错误的一个清单,并渲染成一个ul。看上去可能像: <ul class="errorlist"> <li>Sender is required.</li> </ul>
补充练习:
from django.shortcuts import render # Create your views here. from .models import UserInfor from django.forms import ModelForm from django import forms from .models import * print(City.objects.all().values_list("id","name")) # class RegForm(forms.Form): # user = forms.CharField(max_length=32) # #gender_tuple=(0,'上海'),(1,'北京'),(2,'保定') # gender = forms.ChoiceField(choices =City.objects.all().values_list("id","name")) # # def __init__(self,*args,**kwargs): # super(RegForm,self).__init__(*args,**kwargs) # #print("Ok") # print(self.fields["gender"].choices) # self.fields["gender"].choices=City.objects.all().values_list("id","name") ''' class UserInfor(models.Model): user=models.CharField(max_length=32) gender=models.IntegerField(choices=((1,"男"),(2,"女"))) city=models.ForeignKey("City",default=1) roles=models.ManyToManyField("Roles",default=1) ||||| class UserInfor(forms.Form): user=forms.CharField() gender=forms.TypedChoiceField(choices=((1,"男"),(2,"女"))) city=forms.ModelChoiceField(choices=City.objects.all()) roles=forms.ModelMultipleChoiceField(choices=Roles.objects.all()) ''' class RegForm(ModelForm): class Meta: model=UserInfor fields="__all__" def reg(reqeust): form=RegForm() print(form.fields) return render(reqeust,"reg.html",{"form":form})