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标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...
随机推荐
- 七、OIDC
在 OAuth 中,这些授权被称为scope. OpenID-Connect也有自己特殊的scope--openid , 它必须在第一次请求“身份鉴别服务器”(Identity Provider,简称 ...
- Pythonf反射
Python中,反射有4个方法.分别是:hasattr().getattr().setattr()和delattr(). hasattr() 定义 hasattr()函数用于判断对象是否包含对应的属性 ...
- C# 使用猫拨打电话
主窗口一个textbox与btnstart按钮 代码是使用别人!只是去掉部分不用的!只用于拨号!用于辅助打电话! form1 using System; using System.Collection ...
- vs code常用插件(python)
1.chinese 作用:vscode设置为中文. 使用方法:Ctrl+Shift+P:输入 "config":选择zh 2.python 作用:调试 3.autoDocstrin ...
- MUI 自定义从底部弹出的弹出框内容
最近做的项目都是在使用mui做手机网页,大致是下面的这种弹出效果 首先,引入 mui.css或者mui.min.css 引入 mui.min.js或者mui.js 第二步:<a href=&qu ...
- UNP学习第九章 基本名字与地址转换
之前都用数值地址来表示主机(206.6.226.33),用数值端口号来标识服务器. 然而,我们应该使用名字而不是数值:名字比较容易记,数值地址可以改变但名字保持不变. 随着往IPv6上转移,数值地址变 ...
- hdu 4609 3-idiots(FFT+去重处理)
3-idiots Problem Description King OMeGa catched three men who had been streaking in the street. Look ...
- prototype、proto和constructor 关系
记录: 1.构造函数:如下,Foo()就是一个构造函数 function Foo(){} 2.prototype:每一个构造函数都有一个属性叫prototype,相当于一个指针,指向它的原型对象 Fo ...
- Webx.0-Web3.0:Web3.0
ylbtech-Webx.0-Web3.0:Web3.0 Web3.0只是由业内人员制造出来的概念词语,最常见的解释是,网站内的信息可以直接和其他网站相关信息进行交互,能通过第三方信息平台同时对多家网 ...
- flask-sqlalchemy报错 Object '<User at xxxx>' is already attached to session '1' (this is '2')
报错: Object '<User at xxxx>' is already attached to session '1' (this is '2') 结论: 两个不同的db ...