Form与ModelForm中的插件使用
一、Form插件的使用
(一)widget参数
from .models import * from django import forms
from django.forms import widgets
class BookForm(forms.Form): email=forms.EmailField()
title = forms.CharField(max_length=32,label="书籍名称")
price = forms.DecimalField(max_digits=4, decimal_places=2,label="价格") # 34.91
pub_date = forms.DateField(label="日期",
widget=widgets.TextInput(attrs={"type":"date"}) #插件
)
book_type=forms.ChoiceField(choices=((1,"自然科学"),(2,"社会学科"),(3,"其他")))
publish=forms.ModelChoiceField(queryset=Publish.objects.all())
authors=forms.ModelMultipleChoiceField(queryset=Author.objects.all())
在date字段中使用了插件,参数是widget,可以从源码角度来看看是为什么?
class DateField(BaseTemporalField):
widget = DateInput
input_formats = formats.get_format_lazy('DATE_INPUT_FORMATS')
default_error_messages = {
'invalid': _('Enter a valid date.'),
} def to_python(self, value):
"""
Validate that the input can be converted to a date. Return a Python
datetime.date object.
"""
if value in self.empty_values:
return None
if isinstance(value, datetime.datetime):
return value.date()
if isinstance(value, datetime.date):
return value
return super().to_python(value) def strptime(self, value, format):
return datetime.datetime.strptime(value, format).date()
DateField
DateField的基类是Field,在Field中接收插件参数为widget:
class Field:
widget = TextInput # Default widget to use when rendering this type
...
...
def __init__(self, *, required=True, widget=None, label=None, initial=None,
help_text='', error_messages=None, show_hidden_initial=False,
validators=(), localize=False, disabled=False, label_suffix=None): self.required, self.label, self.initial = required, label, initial
self.show_hidden_initial = show_hidden_initial
self.help_text = help_text
self.disabled = disabled
self.label_suffix = label_suffix
widget = widget or self.widget
if isinstance(widget, type):
widget = widget()
else:
widget = copy.deepcopy(widget)
...
... super().__init__()
显然,参数中传入的是widgets.TextInput,所以进入到widgets模块下找TextInput类:
class TextInput(Input):
input_type = 'text'
template_name = 'django/forms/widgets/text.html'
其基类是Input:
class Input(Widget):
"""
Base class for all <input> widgets.
"""
input_type = None # Subclasses must define this.
template_name = 'django/forms/widgets/input.html' def __init__(self, attrs=None):
if attrs is not None:
attrs = attrs.copy()
self.input_type = attrs.pop('type', self.input_type)
super().__init__(attrs) def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
context['widget']['type'] = self.input_type
return context
Input
基类中取出input_type,并且拷贝attrs属性。
(二)触发widget渲染
渲染text.html,其实就是渲染input.html
<input type="{{ widget.type }}" name="{{ widget.name }}"
{% if widget.value != None %}
value="{{ widget.value|stringformat:'s' }}"
{% endif %}
{% include "django/forms/widgets/attrs.html" %} />
attrs.html
{% for name, value in widget.attrs.items %}
{% if value is not False %}
{{ name }}
{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}
{% endif %}
{% endfor %}
可是,在什么时候触发渲染呢?
其实就是在渲染每一BoundField对象(BoundField类位于django.forms.boundfield.BoundField),所以可以看看BoundField类中的方法:
class BoundField:
"A Field plus data"
def __init__(self, form, field, name):
self.form = form
self.field = field
self.name = name
self.html_name = form.add_prefix(name)
self.html_initial_name = form.add_initial_prefix(name)
self.html_initial_id = form.add_initial_prefix(self.auto_id)
if self.field.label is None:
self.label = pretty_name(name)
else:
self.label = self.field.label
self.help_text = field.help_text or '' def __str__(self):
"""Render this field as an HTML widget."""
if self.field.show_hidden_initial:
return self.as_widget() + self.as_hidden(only_initial=True)
return self.as_widget() #在这里就和widgets联系上了 #调用widget中的render
def as_widget(self, widget=None, attrs=None, only_initial=False):
"""
Render the field by rendering the passed widget, adding any HTML
attributes passed as attrs. If a widget isn't specified, use the
field's default widget.
"""
if not widget:
widget = self.field.widget if self.field.localize:
widget.is_localized = True attrs = attrs or {}
attrs = self.build_widget_attrs(attrs, widget)
auto_id = self.auto_id
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
if not only_initial:
attrs['id'] = auto_id
else:
attrs['id'] = self.html_initial_id if not only_initial:
name = self.html_name
else:
name = self.html_initial_name kwargs = {}
if func_supports_parameter(widget.render, 'renderer') or func_accepts_kwargs(widget.render):
kwargs['renderer'] = self.form.renderer
else:
warnings.warn(
'Add the `renderer` argument to the render() method of %s. '
'It will be mandatory in Django 2.1.' % widget.__class__,
RemovedInDjango21Warning, stacklevel=2,
)
return widget.render(
name=name,
value=self.value(),
attrs=attrs,
**kwargs
)
调用WIdget中的render(Widget位于django.forms.widgets.Widget):
def render(self, name, value, attrs=None, renderer=None):
"""Render the widget as an HTML string."""
context = self.get_context(name, value, attrs)
return self._render(self.template_name, context, renderer) def _render(self, template_name, context, renderer=None):
if renderer is None:
renderer = get_default_renderer()
return mark_safe(renderer.render(template_name, context))
从这里可以知道widget的name就是self.name,是forms字段名称,value是self.initial。
def value(self):
"""
Return the value for this BoundField, using the initial value if
the form is not bound or the data otherwise.
"""
data = self.initial
if self.form.is_bound:
data = self.field.bound_data(self.data, data)
return self.field.prepare_value(data)
value
所以,pub_date标签渲染为:
<input type="date" name="pub_date" >
二、ModelForm插件的使用
from django.forms import widgets as wid
class BookForm(ModelForm):
class Meta:
model=Book
fields="__all__"
labels={"title":"书籍名称", "price":"价格"}
widgets={
"title":wid.TextInput(attrs={"class":"form-control"}),
"price":wid.TextInput(attrs={"class":"form-control"}),
"pub_date":wid.TextInput(attrs={"class":"form-control","type":"date"}),
"publish":wid.Select(attrs={"class":"form-control"}),
"authors":wid.SelectMultiple(attrs={"class":"form-control"}),
}
在ModelForm中使用widgets参数,看看源码中参数的定义:
#自定义ModelForm中Meta中的可传参数
class ModelFormOptions:
def __init__(self, options=None):
self.model = getattr(options, 'model', None)
self.fields = getattr(options, 'fields', None)
self.exclude = getattr(options, 'exclude', None)
self.widgets = getattr(options, 'widgets', None) #插件参数
self.localized_fields = getattr(options, 'localized_fields', None)
self.labels = getattr(options, 'labels', None)
self.help_texts = getattr(options, 'help_texts', None)
self.error_messages = getattr(options, 'error_messages', None)
self.field_classes = getattr(options, 'field_classes', None)
另外,在自定义ModelForm的元类中已经生成了对应fields,并且每个字段与widget完成了映射。
class ModelFormMetaclass(DeclarativeFieldsMetaclass):
def __new__(mcs, name, bases, attrs):
...
... #得到字段
fields = fields_for_model(
opts.model, opts.fields, opts.exclude, opts.widgets,
formfield_callback, opts.localized_fields, opts.labels,
opts.help_texts, opts.error_messages, opts.field_classes,
# limit_choices_to will be applied during ModelForm.__init__().
apply_limit_choices_to=False,
) ...
...
new_class.base_fields = fields return new_class
这样剩下的可以参考Form中widget的流程了。
Form与ModelForm中的插件使用的更多相关文章
- django中的Form和ModelForm中的问题
django的Form组件中,如果字段中包含choices参数,请使用两种方式实现数据源实时更新 方法一:重写构造方法,在构造方法中重新去获取值 class UserForm(forms.Form): ...
- {Django基础十之Form和ModelForm组件}一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 ModelForm
Django基础十之Form和ModelForm组件 本节目录 一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 Model ...
- Django之 Form和ModelForm组件
01-Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用 ...
- Django Form和ModelForm组件
Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...
- day063 form 和modelform组件
注册功能: (写一个简单的注册功能,要求用户名长度不得小于6位.) 普通方式写注册功能 views视图下: def register(request): error_msg=' ' if reque ...
- Django之Form、ModelForm 组件
Django之Form.ModelForm 组件 一.Form组件: django框架提供了一个form类,来处理web开发中的表单相关事项.众所周知,form最常做的是对用户输入的内容进行验证,为此 ...
- Django基础十之Form和ModelForm组件
一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户 ...
- python笔记-20 django进阶 (model与form、modelform对比,三种ajax方式的对比,随机验证码,kindeditor)
一.model深入 1.model的功能 1.1 创建数据库表 1.2 操作数据库表 1.3 数据库的增删改查操作 2.创建数据库表的单表操作 2.1 定义表对象 class xxx(models.M ...
- Form和ModelForm组件
Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...
随机推荐
- 2019CCPC网络赛 HDU6705 - path K短路
题意:给出n个点m条边的有向图,问图上第K短路的长度是多少(这里的路可以经过任何重复点重复边). 解法:解法参考https://blog.csdn.net/Ratina/article/details ...
- js对象的深度拷贝
//判断对象的类型 Array Object Function String Number ..... function getObjType(obj){ return Object.prototyp ...
- 目标检测中roi的有关操作
1.roi pooling 将从rpn中得到的不同Proposal大小变为fixed_length output, 也就是将roi区域的卷积特征拆分成为H*W个网格,对每个网格进行maxpooling ...
- 阿里云公共DNS正式发布支持IPv6的版本
在10月23日召开的GNTC 2019全球网络技术大会IPv6分论坛上,阿里云高级技术专家张先国宣布支持阿里公共DNS的IPv6版本正式发布,即阿里公共DNS在保持IPv4 稳定解析服务的基础上(An ...
- springcloud的config
CONFIG服务端 加入依赖: <dependency> <groupId>org.springframework.cloud</groupId> <arti ...
- <Jmeter入门不放弃>之<1.认识jmeter>
大家这里参考学习的时候,我就不在这里配截图了,因为需要你打开工具根据文档自己去找,,才有印象,大家一定要启动JMeter! 一.Jmeter是什么 由 Apache 组织开发,基于JAVA压力测试工具 ...
- 【Java架构:基础技术】一篇文章搞掂:Idea
一.使用技巧 1.1.配置Maven 打开File-Settings打开设置界面 1.2.配置JDK JDK可以设置默认版本,也可以设置针对某个项目 分别对应File-Other Setting-De ...
- 2018icpc南京/gym101981 I Magic Potion
题意: 若干个勇士,每个勇士只能杀特定的怪物.每个勇士只能杀1个怪,但是有一些药,喝了药之后能再杀一个,每个勇士只能喝一瓶药.问你最多杀多少怪. 题解: 按照如下建图套网络流板即可. 网上有题解说套D ...
- struts2 paramsPrepareParamsStack拦截器简化代码(源码分析)
目录 一.在讲 paramsPrepareParamsStack 之前,先看一个增删改查的例子. 1. Dao.java准备数据和提供增删改查 2. Employee.java 为model 3. E ...
- 用JOptionPane类实现各种对话框
用JOptionPane类实现各种对话框 运行结果: 下面部分参考: JOptionPane类提示框的一些常用的方法 - - ITeye博客 http://847353020-qq-com.itey ...