【python】-- Django Form
Django Form
Django的Form主要具有一下几大功能:
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
- 初始化页面显示内容(自定义样式)
一、Form 简单示例:
1、view中创建Form类并进行函数处理
from django import forms # 导入forms class FM(forms.Form): user = forms.CharField() pwd = forms.CharField() email = forms.EmailField() def fm(request): if request.method == "GET": obj = FM() return render(request, 'fm.html', {'obj': obj}) elif request.method == "POST": # 获取用户所有数据 # 每条数据请求的验证 # 成功:获取所有的正确的信息 # 失败:显示错误信息 obj = FM(request.POST) # 生成from表单验证对象实例 r1 = obj.is_valid() # 获取obj对象是否有效 if r1: # obj.cleaned_data print(r1) print(obj.changed_data) else: print(r1) print(obj.errors.as_json()) # 错误信息字典形式 # {"user": [{"message": "This field is required.", "code": "required"}], # "pwd": [{"message": "This field is required.", "code": "required"}], # "email": [{"message": "This field is required.", "code": "required"}]} print(obj.errors['user'][0]) return redirect("/fm/")
2、生成HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/fm/" method="POST"> {% csrf_token %} {# <!--第一种 input框形式-->#} {# <p><input type="text" name="user"/> {{ obj.errors.user.0 }}</p> <!--user pwd email 必须要跟视图中的继承forms.Form类中的相应实例名称一致-->#} {# <p><input type="text" name="pwd"/> {{ obj.errors.pwd.0 }}</p>#} {# <p><input type="text" name="email"/> {{ obj.errors.email.0 }}</p>#} <!--第二种 obj.user框形式--> <p>{{ obj.user }} {{ obj.errors.user.0 }}</p> <!-- 类似于view视图中的 obj.errors['user'][0]--> <p>{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p> <p>{{ obj.email }}{{ obj.errors.email.0 }}</p> {# <!--第三种 obj.as_p、obj.as_ul、 obj.as_table(需要在外面添加table标签)框形式,生成方便,自定义样式不强-->#} {# {{ obj.as_p }}#} {# {{ obj.as_ul }}#} {# <table>#} {# {{ obj.as_table }}#} {# </table>#} <input type="submit" value="提交" /> </form> </body> </html>
二、Form类
创建Form类时,主要涉及到 fields【字段】 和 wiegets【插件】,功能特性:字段用于对用户请求数据的验证,插件用于自动生成HTML(保留上一次提交的数据)。使用场景:1、在新url方式操作时,字段和插件都需要用到,因为在from提交之后,页面也会被刷新,而插件可以保留上一次的提交数据。2、在用Ajax请求操作时,可以只用到字段的验证功能,因为Ajax请求页面不会刷新,上一次提交数据仍然保留在页面,当然在用Ajax请求操作时也可以使用插件。
1、Django内置字段如下:
1 Field 2 required=True, 是否允许为空 3 widget=None, HTML插件 4 label=None, 用于生成Label标签或显示内容 5 initial=None, 初始值 6 help_text='', 帮助信息(在标签旁边显示) 7 error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} 8 show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) 9 validators=[], 自定义验证规则 10 localize=False, 是否支持本地化 11 disabled=False, 是否可以编辑 12 label_suffix=None Label内容后缀 13 14 15 CharField(Field) 16 max_length=None, 最大长度 17 min_length=None, 最小长度 18 strip=True 是否移除用户输入空白 19 20 IntegerField(Field) 21 max_value=None, 最大值 22 min_value=None, 最小值 23 24 FloatField(IntegerField) 25 ... 26 27 DecimalField(IntegerField) 28 max_value=None, 最大值 29 min_value=None, 最小值 30 max_digits=None, 总长度 31 decimal_places=None, 小数位长度 32 33 BaseTemporalField(Field) 34 input_formats=None 时间格式化 35 36 DateField(BaseTemporalField) 格式:2015-09-01 37 TimeField(BaseTemporalField) 格式:11:12 38 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 39 40 DurationField(Field) 时间间隔:%d %H:%M:%S.%f 41 ... 42 43 RegexField(CharField) 44 regex, 自定制正则表达式 45 max_length=None, 最大长度 46 min_length=None, 最小长度 47 error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} 48 49 EmailField(CharField) 50 ... 51 52 FileField(Field) 53 allow_empty_file=False 是否允许空文件 54 55 ImageField(FileField) 56 ... 57 注:需要PIL模块,pip3 install Pillow 58 以上两个字典使用时,需要注意两点: 59 - form表单中 enctype="multipart/form-data" 60 - view函数中 obj = MyForm(request.POST, request.FILES) 61 62 URLField(Field) 63 ... 64 65 66 BooleanField(Field) 67 ... 68 69 NullBooleanField(BooleanField) 70 ... 71 72 ChoiceField(Field) 73 ... 74 choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) 75 required=True, 是否必填 76 widget=None, 插件,默认select插件 77 label=None, Label内容 78 initial=None, 初始值 79 help_text='', 帮助提示 80 81 82 ModelChoiceField(ChoiceField) 83 ... django.forms.models.ModelChoiceField 84 queryset, # 查询数据库中的数据 85 empty_label="---------", # 默认空显示内容 86 to_field_name=None, # HTML中value的值对应的字段 87 limit_choices_to=None # ModelForm中对queryset二次筛选 88 89 ModelMultipleChoiceField(ModelChoiceField) 90 ... django.forms.models.ModelMultipleChoiceField 91 92 93 94 TypedChoiceField(ChoiceField) 95 coerce = lambda val: val 对选中的值进行一次转换 96 empty_value= '' 空值的默认值 97 98 MultipleChoiceField(ChoiceField) 99 ... 100 101 TypedMultipleChoiceField(MultipleChoiceField) 102 coerce = lambda val: val 对选中的每一个值进行一次转换 103 empty_value= '' 空值的默认值 104 105 ComboField(Field) 106 fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式 107 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) 108 109 MultiValueField(Field) 110 PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用 111 112 SplitDateTimeField(MultiValueField) 113 input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] 114 input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] 115 116 FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中 117 path, 文件夹路径 118 match=None, 正则匹配 119 recursive=False, 递归下面的文件夹 120 allow_files=True, 允许文件 121 allow_folders=False, 允许文件夹 122 required=True, 123 widget=None, 124 label=None, 125 initial=None, 126 help_text='' 127 128 GenericIPAddressField 129 protocol='both', both,ipv4,ipv6支持的IP格式 130 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 131 132 SlugField(CharField) 数字,字母,下划线,减号(连字符) 133 ... 134 135 UUIDField(CharField) uuid类型 UUID是根据MAC以及当前时间等创建的不重复的随机字符串 136 ...
2、Django内置插件:
1 TextInput(Input) 2 NumberInput(TextInput) 3 EmailInput(TextInput) 4 URLInput(TextInput) 5 PasswordInput(TextInput) 6 HiddenInput(TextInput) 7 Textarea(Widget) 8 DateInput(DateTimeBaseInput) 9 DateTimeInput(DateTimeBaseInput) 10 TimeInput(DateTimeBaseInput) 11 CheckboxInput 12 Select 13 NullBooleanSelect 14 SelectMultiple 15 RadioSelect 16 CheckboxSelectMultiple 17 FileInput 18 ClearableFileInput 19 MultipleHiddenInput 20 SplitDateTimeWidget 21 SplitHiddenDateTimeWidget 22 SelectDateWidget
2.1、常用的内置插件演示:
1 # 单radio,值为字符串 2 # user = fields.CharField( 3 # initial=2, 4 # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) 5 # ) 6 7 # 单radio,值为字符串 8 # user = fields.ChoiceField( 9 # choices=((1, '上海'), (2, '北京'),), 10 # initial=2, 11 # widget=widgets.RadioSelect 12 # ) 13 14 # 单select,值为字符串 15 # user = fields.CharField( 16 # initial=2, 17 # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) 18 # ) 19 20 # 单select,值为字符串 21 # user = fields.ChoiceField( 22 # choices=((1, '上海'), (2, '北京'),), 23 # initial=2, 24 # widget=widgets.Select 25 # ) 26 27 # 多选select,值为列表 28 # user = fields.MultipleChoiceField( 29 # choices=((1,'上海'),(2,'北京'),), 30 # initial=[1,], 31 # widget=widgets.SelectMultiple 32 # ) 33 34 35 # 单checkbox 36 # user = fields.CharField( 37 # widget=widgets.CheckboxInput() 38 # ) 39 40 41 # 多选checkbox,值为列表 42 # user = fields.MultipleChoiceField( 43 # initial=[2, ], 44 # choices=((1, '上海'), (2, '北京'),), 45 # widget=widgets.CheckboxSelectMultiple 46 # )
2.2、Form操作动态Select数据:
1 # forms.py 在app目录下创建forms.py文件,来专门存放form验证的代码 2 from django.forms import widgets,forms,fields 3 from app01 import models 4 5 class UserForm(forms.Form): 6 7 name = fields.CharField( 8 required=False, 9 widget=widgets.TextInput(attrs={'class':'c1'}) 10 ) 11 12 email = fields.EmailField( 13 max_length=12, 14 widget=widgets.TextInput(attrs={"class":"c2"}) 15 ) 16 17 user_type = fields.ChoiceField 18 ### 第一种form动态获取select数据 19 #静态变量,仅在程序第一次加载时执行,从数据库读取数据保存至内存,重启服务才能从数据库获取最新数据 20 # choices=models.UserType.objects.values_list('id','type_name'), 21 22 ### 第二种form动态获取select数据,自定义构造方法, 23 choices=[], 24 widget=widgets.Select 25 ) 26 27 user_type2 = fields.CharField(widget=widgets.Select(choices=[])) #fields['user_type2'].widget.choices 28 29 def __init__(self,*args,**kwargs): 30 super(UserForm,self).__init__(*args,**kwargs) 31 32 # 构造方法中实例变量会在每次实例化后执行 33 self.fields["user_type"].choices = models.UserType.objects.values_list('id','type_name') 34 self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','type_name') 35 36 37 38 # view.py 在view.py视图函数中去调用From验证 39 40 from django.shortcuts import render 41 from app01 import models 42 43 def index(request): 44 from app01.forms import UserForm 45 ### 第一种form动态获取select数据 46 #obj = UserForm() # 实例化UserForm类 47 # obj.fields["user_type"].choices=models.UserType.objects.values_list('id','type_name') #每次刷新web页面就相当于实例化一次UserForm类,从而从数据库获取最新数据 48 49 ### 第二种form动态获取select数据,自定义构造方法 50 obj = UserForm() #实例化UserForm类,这里只需要实例化,而form UserForm类中重写的构造方法中的实例变量会在每次实例化之后执行一次 51 return render(request,'index.html',{'obj':obj}) 52 53 54 55 #HTML 56 <body> 57 <p>{{ obj.name }}</p> 58 <p>{{ obj.email }}</p> 59 <p>{{ obj.user_type }}</p> 60 <p>{{ obj.user_type2 }}</p> 61 </body>
1 ##form.py 2 #ModelChoiceField具体字段如下: 3 ModelChoiceField(ChoiceField) 4 ... django.forms.models.ModelChoiceField 5 queryset, # 查询数据库中的数据 6 empty_label="---------", # 默认空显示内容 7 to_field_name=None, # HTML中value的值对应的字段 8 limit_choices_to=None # ModelForm中对queryset二次筛选 ### 9 10 11 12 from django.forms import widgets,forms,fields 13 from django.forms.models import ModelChoiceField #django自己帮我们提供的 14 15 class UserForm(forms.Form): 16 user_type3 = ModelChoiceField( 17 queryset=models.UserType.objects.all(), 18 to_field_name="id", #html中的value的值的对应字段,一般情况下只用id 19 empty_label="请选择用户类型", #默认空显示内容 20 ) 21 22 23 ##ModelChoiceField必须跟model中的__str__函数想结合使用: 24 class UserType(models.Model): 25 type_name = models.CharField(max_length=32) 26 27 def __str__(self): #必须跟__str__这个函数结合使用 28 return self.type_name 29 30 31 32 33 34 #view.py 35 36 def index(request): 37 38 from app01.forms import UserForm 39 obj = UserForm() 40 41 return render(request,'index.html',{'obj':obj}) 42 43 44 #HTML 45 <body> 46 <p>{{ obj.user_type3 }}</p> 47 </body>
3、Form内置钩子进行验证:
django form中还预留了钩子,主要有三个类型的钩子:_clean_fields (单个字段验证,,如:登录页面user or password字段)、_clean_fields (整体验证,如:登录页面整体)、_post_clean(预留的钩子,主要坐收尾工作)
3.1、_clean_fields
1 from app01 import models 2 from django.core.exceptions import ValidationError #源码里面抛出的异常 3 class RegisterForm(forms.Form): 4 user = fields.CharField() #下面的方法要想执行,先通过这边正则验证 5 email = fields.EmailField() 6 #根据源码,我们知道在我们自己自定义的form中,是 定义clean_字段名 方法,去验证,然后赋值给 cleaned_data 7 #clean_%s 这个函数必须要有返回值,赋值给self.cleaned_data['%s'] 8 def clean_user(self): 9 #注册的时候,如果存在此用户,则报错,没有,则继续执行 10 c = models.User.objects.filter(name=self.cleaned_data['user'].count()) 11 if not c: 12 return self.cleaned_data['user'] 13 else: 14 raise ValidationError('用户名已经存在',code="xxxx") #存在就包异常 15 16 17 def clean_email(self): 18 19 return self.cleaned_data['email'] #这边必须返回一个值
3.2、_clean_form
1 from app01 import models 2 from django.core.exceptions import ValidationError #源码里面抛出的异常 3 class RegisterForm(forms.Form): 4 user = fields.CharField() #下面的方法要想执行,先通过这边正则验证 5 pwd = fields.CharField() 6 7 8 def clean(self): 9 c = models.User.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count() 10 if not c: 11 return self.cleaned_data #这边必须有一个返回值,因为源码里面有返回值 12 else: 13 raise ValidationError("用户名或密码错误",code="xxxxx") #这个异常应该给整体,不应该给某一个字段
3.3、单个字段错误提示和form整体错误提示
1 obj.errors: 2 { 3 #self._clean_form() 返回的错误信息,也就是整体返回的错误信息,有的地方写成: NON_FIFLD_ERRORS:[],其实就是代指的__all__ 4 '__all__':[], 5 # clean_user和clean_pwd返回的错误信息,就是单个验证返回的错误信息 6 'user':[{'code':"required",'message':'xxxx'}], 7 'pwd':[{'code':"required",'message':'xxxx'}] 8 }
4、自定义验证规则:
from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator class MyForm(Form): user = fields.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], )
import re from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.exceptions import ValidationError # 自定义验证规则 def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): raise ValidationError('手机号码格式错误') class PublishForm(Form): title = fields.CharField(max_length=20, min_length=5, error_messages={'required': '标题不能为空', 'min_length': '标题最少为5个字符', 'max_length': '标题最多为20个字符'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': '标题5-20个字符'})) # 使用自定义验证规则 phone = fields.CharField(validators=[mobile_validate, ], error_messages={'required': '手机不能为空'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'手机号码'})) email = fields.EmailField(required=False, error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
# 自定义方法 from django import forms from django.forms import fields from django.forms import widgets from django.core.exceptions import ValidationError from django.core.validators import RegexValidator class FInfo(forms.Form): username = fields.CharField(max_length=5, validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], ) email = fields.EmailField() def clean_username(self): """ Form中字段中定义的格式匹配完之后,执行此方法进行验证 :return: """ value = self.cleaned_data['username'] if "666" in value: raise ValidationError('666已经被玩烂了...', 'invalid') return value
#同时生成多个标签进行验证 from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator ############## 自定义字段 ############## class PhoneField(fields.MultiValueField): def __init__(self, *args, **kwargs): # Define one message for all fields. error_messages = { 'incomplete': 'Enter a country calling code and a phone number.', } # Or define a different message for each field. f = ( fields.CharField( error_messages={'incomplete': 'Enter a country calling code.'}, validators=[ RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'), ], ), fields.CharField( error_messages={'incomplete': 'Enter a phone number.'}, validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')], ), fields.CharField( validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')], required=False, ), ) super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args, **kwargs) def compress(self, data_list): """ 当用户验证都通过后,该值返回给用户 :param data_list: :return: """ return data_list ############## 自定义插件 ############## class SplitPhoneWidget(widgets.MultiWidget): def __init__(self): ws = ( widgets.TextInput(), widgets.TextInput(), widgets.TextInput(), ) super(SplitPhoneWidget, self).__init__(ws) def decompress(self, value): """ 处理初始值,当初始值initial不是列表时,调用该方法 :param value: :return: """ if value: return value.split(',') return [None, None, None]
5、Form内置序列化错误信息:
1 #form.py 2 rom django import forms 3 from django.forms import fields,widgets 4 5 class LoginForm(forms.Form): 6 username = fields.CharField() #这跟login.html中的input标签的name属性的值一致 7 password = fields.CharField( 8 max_length=64, 9 min_length=12 10 ) 11 12 13 14 15 16 17 #view 中的login 函数 18 #第一种 使用ErrorDict中的as_json函数,不过在HTML中相应获取错误信息需要反解两次 19 from django.shortcuts import render,HttpResponse 20 import json 21 def login(request): 22 ret = {'status':True,'error':None,'data':None} 23 if request.method == "GET": 24 return render(request,'login.html') 25 elif request.method == "POST": 26 obj = LoginForm(request.POST) 27 if obj.is_valid(): 28 print(obj.cleaned_data) 29 else: 30 # print(type(obj.errors)) 通过打印类型得知是属于ErrorDict 31 from django.forms.utils import ErrorDict #通过源码得知:as_data 返回的是原生的字典,as_json()是类似json格式的字符串 32 ret['error'] = obj.errors.as_json() 33 return HttpResponse(json.dumps(ret)) #因为as_json()和json.dumps 相当于序列化了两次 34 35 36 37 #第二张自定义JsonCustomEncoder类 38 from django.core.exceptions import ValidationError 39 import json 40 class JsonCustomEncoder(json.JSONEncoder): #直接在cls=JsonCustomEncoder类名,去序列化复杂的数据类型 41 def default(self,field): 42 if isinstance(field,ValidationError): # 43 # # from django.core.exceptions import ValidationError #看一下这个异常,发现field的字段和错误信息都保存在这个ValidationError对象里 44 return {'code':field.code,'messages':field.messages} 45 else: 46 return json.JSONEncoder.default(self,field) 47 48 49 50 from django.shortcuts import render,HttpResponse 51 import json 52 53 def login(request): 54 ret = {'status':True,'error':None,'data':None} 55 if request.method == "GET": 56 return render(request,'login.html') 57 elif request.method == "POST": 58 obj = LoginForm(request.POST) 59 if obj.is_valid(): 60 print(obj.cleaned_data) 61 else: 62 ret['error'] = obj.errors.as_data() 63 # for k,v in obj.errors.as_data().items(): 64 # print(k,v) 通过打印发现as_data后 value是一个ValidationError对象 65 # ret = {'k1':'v1','k2':ValueError()} #像这种复杂数据类型,json是不能序列化的,我们只能做局部处理 66 #这边cls 是序列化的时候,对每一个字段序列化的时候,都会调用一个它的default方法,因此重写JsonCustomEncoder类中default方法来进行复杂情况下的序列化操作 67 result = json.dumps(ret,cls=JsonCustomEncoder) 68 return HttpResponse(result) 69 70 71 72 73 #HTML 74 """ 75 <body> 76 <form id="fm"> 77 {% csrf_token %} 78 <p><input type="text" name="username" /></p> #这边username 需要跟 from 里面的字段 是一模一样 79 <p><input type="text" name="password" /></p> 80 <a id="submit">提交</a> 81 </form> 82 83 <script src="/static/jquery-1.12.4.js"></script> 84 <script> 85 $(function(){ 86 $('#submit').click(function(){ 87 $.ajax({ 88 url:'/login/', 89 type:'post', 90 data:$('#fm').serialize(), 91 sucess:function(arg){ 92 //console.log(arg); 93 arg = JSON.parse(arg); 94 console.log(arg) 95 }, 96 error:function(){ 97 98 } 99 }) 100 }) 101 }) 102 </script> 103 </body>""" 104 105 106 107 108 #返回的数据类型为: 109 110 "{\"data\": null, \"status\": true, \"error\": {\"username\": [{\"code\": \"required\", \"messages\": [\"This field is required.\"]}], 111 \"password\": [{\"code\": \"required\", \"messages\": [\"This field is required.\"]}]}}"
6、Form类中的fields、widgets 简单示例:
a、Form类:
from django import forms # 导入forms from django.forms import widgets # 导入插件 from django.forms import fields # 导入字段,以后对于像charField、EmailField等字段格式的处理不需要在通过form.进行定义了,而是通过fields进行定义 class FM(forms.Form): # 字段本身只做验证 user = fields.CharField( error_messages={'required': '用户名不能为空.'}, # 定义错误信息的提示语,required为定义输入框为空的提示语 # widget=widgets.Textarea(attrs={'class': 'c1'}), # 导入插件中的多行文本输入,并定义样式 label="用户名", # 定义标签名称 ) pwd = fields.CharField( max_length=12, # 定义字符最大、最近小字符长度,及相应错误提示语 min_length=6, error_messages={'required': '密码不能为空.', 'min_length': '密码长度不能小于6', "max_length": '密码长度不能大于12'}, widget=widgets.PasswordInput(attrs={'class': 'c2'}) # 导入插件中的密码非明文输入,并定义样式 ) email = fields.EmailField(error_messages={'required': '邮箱不能为空.', 'invalid': "邮箱格式错误"}) # invalid定义输入框无效是的提示语 f = fields.FileField() # 文件上传 p = fields.FilePathField(path='app01') # 将路径下的全部文件进行展示 city1 = fields.ChoiceField( # 单项选择框 choices=[(0, '上海'), (1, '广州'), (2, '东莞')] ) city2 = fields.MultipleChoiceField( # 多项选择框 choices=[(0, '上海'), (1, '广州'), (2, '东莞')] )
b.views:
from app01 import models def fm(request): if request.method == "GET": # 从数据库中吧数据获取到 dic = { "user": 'r1', 'pwd': 'password', 'email': 'email@163.com', 'city1': 1, 'city2': [1, 2] } obj = FM(initial=dic) # 初始化操作,通过字典形式传递默认值 return render(request, 'fm.html', {'obj': obj}) elif request.method == "POST": obj = FM(request.POST) r1 = obj.is_valid() if r1: # obj.cleaned_data print(obj.changed_data) # models.UserInf.objects.create(**obj.cleaned_data) else: # errors 继承了ErrorDict类 print(obj.errors.as_json()) # print(obj.errors['user'][0]) return render(request, 'fm.html', {'obj': obj}) return redirect('http://www.ww.qq.com')
c、HTML:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/fm/" method="POST"> {% csrf_token %} <p>{{ obj.user.label}}{{ obj.user }} {{ obj.errors.user.0 }}</p> <!-- 类似于view视图中的 obj.errors['user'][0]--> <p>{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p> <p>{{ obj.email }}{{ obj.errors.email.0 }}</p> <p>{{ obj.f}}</p> <p>{{ obj.p}}</p> <p>{{ obj.city1}}</p> <p>{{ obj.city2}}</p> <input type="submit" value="提交" /> </form> </body> </html>