标签:lse 不能 set 答案 输入 idg from css row
目录
Handle (掌控)一个form是非常复杂的工程,需要做很多功能:不同的类型的数据要有不同的渲染;校验数据;获取检验后的干净数据,并将数据反序列化为相应数据类型如时间对象;保存传递给处理程序等等。Django的forms组件就完成了这些复杂的工作,提供方便的操作form的接口API给我们。
Form对象有很多的API,参考本文API段落。其实每个API都是对应了Form的一个特点。如:form.auto_id 对应就是设置form中表单标签的id属性;form.errors 对应了form的校验和错误信息。等等。官方文档在讲解Form对象API时,也是按照form的功能和特点,来分类介绍每种API的。
绑定数据的form实例和没绑定数据的form实例,他们之间的区别是非常重要的,这影响到了,同一个api或者属性,在templates 引擎渲染和weight作用时所表现出来的内容是不同的。
一个form instance 要么绑定要么没绑定
注意:form对象迭代出来的数据类型。form对象是可迭代的对象,迭代出的是boundfield对象。form对象又是字典类型对象,key是字段名,value是boundfield对象。所以要获取boundfield对象有两种途径,通过for迭代,或者通过字典key访问。以下的field名字没特殊说明,都是boundfield对象。至于获取boundfield对象,刚刚也提到了。下面就来使用它的属性和方法吧:
There are other output options though for the <label>/<input> pairs:
{{ form.as_table }} will render them as table cells wrapped in <tr> tags
{{ form.as_p }} will render them wrapped in <p> tags
{{ form.as_ul }} will render them wrapped in <li> tags
相应的,都必须自己提供table或这ul
pass
所谓校验,就是绑定到form对象的数据,校验其是否符合定义的约束条件。
关于校验方面,要明白的点:
继承关系:
form 的实例,可以是空,也可以提前填充数据。归纳总结form实例化数据主要来自三个方面:
出现modelform 这种form类的情况是这样的:
如果你正在开发基于数据库的web app, 很有可能, 你会创建一个forms 是几乎映射到一个django models的。例如,你可能有一个BlogComment model, 然后,你想创建一个form 让用户通过这个form提交博客评论到BlogComment model的表中。在这个例子中,定义form的field types是一种很冗余的做法(django 哲学之避免冗余),因为你已经定义了model的field type了,可以复用给form用。
因为这个原因, django 提供了一个很有帮助的 class 可以让我们创建一个Form class 通过一个django 的model。这样就复用了django model 中的field的定义。
代码实例:
>>> from django.forms import ModelForm
>>> from myapp.models import Article # 导入自己建好的django model
# 创建form class
>>> class ArticleForm(ModelForm):
... class Meta:
... model = Article
... fields = [‘pub_date‘, ‘headline‘, ‘content‘, ‘reporter‘]
# 创建一个form 用于添加文章
>>> form = ArticleForm()
# 创建一个form 用于改变一个存在的文章
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(instance=article) #
# 上面创建的两个form都可以用于渲染到模版中,分别用于新增和修改。
小结:注意这里modelform和普通form实例化的不同。这里传入一个model object instance作为将用于初始化显示的数据。也可以像普通 form一样,传入initail参数。如果两个参数都传递了的话,那么就变成了第三种情况,不过initial会覆盖instance的初始化。
如果实例化绑定数据时,提供了instance参数,那么在save时就是一个update操作数据库。如果只是给了一个类字典的数据没有instance,那么就是insert新增数据到数据库。
所以,在实例化modelform时,instance参数除了会影响save()的行为,还会影响初始化参数initail的效果。
每一个model field 有一个与之对应的缺省form field。例如, 一个在model中的CharField 被表示为 一个在form中的CharField. 而一个model ManyToManyField 被表示为 一个form的ModelMultipleChoiceField.
缺省对应关系如下图:
正如你所想的,ForeignKey 和 ManyToManyField model field 类型是特殊情况(OneToOne这则不会有这样的特殊情况):
ForeignKey 通过django.forms.ModelChoiceField所表示,这个实际是一个Choice Field,特殊是它的choices 是一个model QuerySet 也就是一个查询出的queryset结果。对于这种ModelChoiceField。在modelform对象层面和ModelChoiceField层面,进行数据绑定和数据clean()校验是不同的。modelform层面实例化是要提供一个queryset作为代替choice参数,利用queryset生成choices。
ModelMutipleChoiceField和ModelChoiceField都有一个可选参数,empty_label 主要用于控制对应select表单的一个空白选项的显示。默认是‘-------------‘
此外,每一个通过model方式生成的modelform field 会设置如下属性:
一个完整的实例定义ModelForm:
# model的
from django.db import models
from django.forms import ModelForm
TITLE_CHOICES = (
(‘MR‘, ‘Mr.‘),
(‘MRS‘, ‘Mrs.‘),
(‘MS‘, ‘Ms.‘),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES) # 注意model和form的字段中都有choices这个属性,理解不同与相关。
birth_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = [‘name‘, ‘title‘, ‘birth_date‘]
class BookForm(ModelForm):
class Meta:
model = Book
fields = [‘name‘, ‘authors‘]
小结:modelform初始化时可以使用initial初始化数据吗?可以的,如果还提供了instance参数用于初始化的话,那么initial优先于instance参数中的值。
modelform的方法和属性除了增加save和save_m2m区别之外,其它和普通form对象API一样。
通过class Meta可以定义覆盖默认的一些modelField的元素。
大致在Meta中的属性有:
model = 映射的model class
fields = [‘fieldname1‘, ‘fieldname2‘...] 全部可以设置为[‘__all__‘]
widgets = {‘fieldname‘: widget_obj,...}
labels = {‘fieldname‘:label_value} 设置渲染时的label值
help_text = {‘fieldname‘: help_string}
error_messages = {‘fieldname‘: {‘校验code‘:错误信息}} 通过这个可以改变错误信息为自定义中文
field_classes = {‘fieldname‘: FieldClass}
如果要完全覆盖一个字段,就在modelfrom中建立一个字段的定义就会完全覆盖modelform默认生成的。
参考:https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/#overriding-the-default-fields
form表单中可以使用input-checkbox 和 select-option 及 input-radio 来实现多值或者提供选择项给用户展示。
form表单基本上可以对应数据库中一个表的一条数据。因为数据库中一个表的数据可能关联到其它表的数据(就是常说的manyTomany,manyToone,oneToone)。要通过form表单,操控数据库一条数据,那么表单就要有展示或者操控数据关系的方式。这种方式就是表单的上面提到的三种表单控件了。
再看回django的form组件。主要就是ChoiceField/ModelChoiceField/ModelMultipleChoiceField的使用。
三者的区别:
上面三种Field对应的表单控件默认都是Select,
而对于要使用input-check,就要给字段重新赋值widget参数为一个Check类型的widget。
Field类实例化对象时,核心参数就五个:
由于错误提示校验是分类的,每种类型字段有哪几种校验错误,可以到官网查询https://docs.djangoproject.com/en/2.1/ref/forms/fields/#built-in-field-classes。
知道要改变哪种类型的错误提示后,就在定义field是设置error_messages={‘错误类型‘: 错误信息!}
这个BoundField 类 ,主要用于展示HTML 或者 用于访问form实例的一个Field对象 属性。
BoundField Used to display HTML or access attributes for a single field of a Form instance.
通过BoundField.field 访问到Field对象。
这个类的__str__() 就是展示 字段的HTML。所以打印BoundField对象就输出了HTML。
通过form访问BoundField对象,可以遍历,也可通过字典key操作,因为form是一个类字典的类型。key就是字段字符串啦。
form中的field负责管理表单数据和表单数据的校验当一个表单被提交后。
和其它的Field不同,有两个特别的Field类型:DateField类与FileField(类似于model中的FileField和ImageField字段比较特别,因为都涉及到文件对象)
在前端页面,需要通过form上传文件,就需要确定form标签的enctype定义了正确的值“multipart/form-data” 现代浏览器对于有文件的上传都会使用这种编码。
这样,才能使用正确的格式编码 form表单中的文件对象和其它数据 到http body中,然后通过http协议传输到服务端,服务端也能正确通过编码方式进行解码,才能正确解析出文件对象和其它数据。
DateField https://docs.djangoproject.com/en/2.0/ref/forms/fields/#django.forms.DateField
在normalized转化到python 对象时,需要特别注意该字段。这个字段会将用户表单中填入的字符串,转化为date对象。(用户的键入只能是字符串形式)。
这个转化过程肯定也是要有依据的,得按照依据规则来,不可能用户随便输入什么字符都能转换换成date对象是吧。所以这个字段在初始化时,需要一个可选参数就是input_formats。提供专业的to_python和to_html 的格式。提供了这些格式,用户输入的时间字符串,就需要按照列表中的格式化提供时间字符串。同时,绑定了值的渲染到页面也是按照其中的格式来的。由于这个时间格式的表示范式,全球各地是不同的,所以会根据整个django项目的F10N参数,来判定默认的input_formats规则是什么。如果F10N=True ,那么input_formats只能用全球同一认可的格式。如下:
[‘%Y-%m-%d‘, # ‘2006-10-25‘
‘%m/%d/%Y‘, # ‘10/25/2006‘
‘%m/%d/%y‘] # ‘10/25/06‘
如果F10N=False,那么就会有更多的格式支持。
[‘%b %d %Y‘, # ‘Oct 25 2006‘
‘%b %d, %Y‘, # ‘Oct 25, 2006‘
‘%d %b %Y‘, # ‘25 Oct 2006‘
‘%d %b, %Y‘, # ‘25 Oct, 2006‘
‘%B %d %Y‘, # ‘October 25 2006‘
‘%B %d, %Y‘, # ‘October 25, 2006‘
‘%d %B %Y‘, # ‘25 October 2006‘
‘%d %B, %Y‘] # ‘25 October, 2006‘
ImageField
对于该字段,实例化时除了带入request.POST外,还需要request.FILES. 也就是要通过form 来handle 上传的文件,需要将文件绑定到form相应的imagefield。
FileField https://docs.djangoproject.com/en/2.0/ref/forms/fields/#django.forms.FileField
对于该字段,实例化时除了带入request.POST外,还需要request.FILES. 也就是要通过form 来handle 上传的文件,需要将文件绑定到form相应的filefield。
FileField可选参数max_length限制文件对象的文件名。allow_empty_file,文件内容可以为空。
# Bound form with an image field
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {‘subject‘: ‘hello‘,
... ‘message‘: ‘Hi there‘,
... ‘sender‘: ‘foo@example.com‘,
... ‘cc_myself‘: True}
>>> file_data = {‘mugshot‘: SimpleUploadedFile(‘face.jpg‘, <file data>)}
## 这里的file_data中的value是一个SimpleuploadedFile对象,对象实例,提供了文件的名字和文件的句柄作为参数。
>>> f = ContactFormWithMugshot(data, file_data)
而在实战中,request为我们handle好了像SimpleuploadFile对象,就是request.FILES.
f = ContactFormWithMugshot(request.POST, request.FILES)
问题来了,那如果是一个modelform呢?怎么实例化这样一个带有文件对象的modelform?答:同普通form一样,多带入一个request.FILES。
modelform 是哪个字段映射到FileField字段呢?
答:也是form的FileField对应
那实例化提供了SimpleuploadFile对象后,有怎么通过save()保存到对应的数据库表中记录呢?就算不是modelform,普通的form,是怎么将上传的文件保存在哪里呢?
猜测,这些可能就是UploadFile对象封装了这些繁琐的事情了吧?后续验证。
特别提醒:注意将form instance api 与 bound field api 对比查看。
form instance api
bound field api
小结:对比后发现,无论是has_changed, as_table ,initail参数等。这些都是form 与 boundfield之间的关系。如form level 的调用会去调用boundfield的对应的调用,has_changed();还是form level的initial初始化字典,影响field的初始化。就连form.as_table / form.as_ul 等,对应都是boundfield的 as_...方式的调用。还有,如果整个form容器里面的boundfield对象都要改变的属性或者特点,那么通过form instance api 进行容器空间全局控制,如果是单个boundfield的改变,就通过对象自己,同时会覆盖form全局的设置。
每种类型的Field class 都有一个默认对应的Widget class。
为什么这样设计?为什么不Field class 把这个干完呢?
因为一个Field class可以有多种Widget表现,即Field 可以和Widget任意匹配,这样能适应的情况就更多了,不然就有超多的细分类型的Field class。同时也可以把一些功能解耦出去。
后面用的多了再总结这一part
django官方也一直没定下怎么渲染表单验证错误信息。
关于设置错误校验错误信息为中文:
pass 就是通过error_messages
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
wid_01 = widgets.TextInput(attrs={"class":"form-control"})
wid_02 = widgets.PasswordInput(attrs={"class":"form-control"})
wid_03 = widgets.EmailInput(attrs={"class":"form-control"})
class RegForms(forms.Form):
username = forms.CharField(min_length=4, widget=wid_01)
password = forms.CharField(min_length=4, widget=wid_01)
r_password = forms.CharField(min_length=4, widget=wid_01)
email = forms.EmailField(widget=wid_03)
telephone = forms.CharField(required=False,widget=wid_01)
school = forms.ChoiceField(choices=[(‘male‘, ‘男‘), (‘female‘, ‘女‘)])
age = forms.BooleanField()
area = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(attrs={‘class‘: ‘checkbox-inline‘}), choices=((‘china‘, ‘中国‘), (‘america‘, ‘美国‘), (‘english‘, ‘英国‘)))
def clean_telephone(self):
val = self.cleaned_data.get(‘telephone‘)
if len(val) == 11 :
return val
else:
raise ValidationError(‘手机号格式错误!‘)
def clean(self):
pwd = self.cleaned_data.get(‘password‘)
r_pwd = self.cleaned_data.get(‘r_password‘)
if pwd and r_pwd:
if pwd == r_pwd :
return self.cleaned_data
else:
raise ValidationError(‘两次密码不相同!‘)
return self.cleaned_data
注意:这里抛出错误是不规范,也是官方不推荐的,官方推荐抛入ValidationError方式,参考:https://docs.djangoproject.com/en/2.1/ref/forms/validation/#raising-validationerror
使用include和 include 。。。 with form = comment_form
You can access the fields of Form instance from its fields attribute:
>>> for row in f.fields.values(): print(row)
...
<django.forms.fields.CharField object at 0x7ffaac632510>
<django.forms.fields.URLField object at 0x7ffaac632f90>
<django.forms.fields.CharField object at 0x7ffaac3aa050>
>>> f.fields[‘name‘]
<django.forms.fields.CharField object at 0x7ffaac6324d0>
You can alter the field of Form instance to change the way it is presented in the form:
>>> f.as_table().split(‘\n‘)[0]
‘<tr><th>Name:</th><td><input name="name" type="text" value="instance" required></td></tr>‘
>>> f.fields[‘name‘].label = "Username" ## 这里修改了CharField对象,最后使用影响了渲染。虽然影响不了绑定的数据。
>>> f.as_table().split(‘\n‘)[0]
‘<tr><th>Username:</th><td><input name="name" type="text" value="instance" required></td></tr>‘
官方文档也说明了boundfield就是wraps包裹form定义的field的。作用就是展示出
标签:lse 不能 set 答案 输入 idg from css row
原文地址:https://www.cnblogs.com/ZJiQi/p/9895728.html