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标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...
随机推荐
- 强大的性能监控pidstat
前言 pidstat 可以监控单个任务.比如CPU.内存.IO.上下文切换.详细参考 man pidstat 安装 yum install sysstat 使用 1.监控所有活动进程 pidstat ...
- Java集合框架是什么?说出一些集合框架的优点?
每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector.Stack.HashTable和Array. 随着集合的广泛使用,Java1.2提出了囊括所有集合接口.实现和算法的集合框架.在 ...
- jQuery效果-隐藏与显示 小方块的移除
html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...
- 一次峰回路转的getshell
扫目录发现 http://www.xxx.test.cn/bak/以及/bak/upload.jsp
- 配置框架spring和SpringDataJpa整合----员工是爹
<!-- 1.dataSource 配置数据库连接池--> <bean id="dataSource" class="com.mchange.v2.c3 ...
- PHP面向对象:instanceof 运算符
http://www.nowamagic.net/php/php_InstanceofOperator.php 在PHP5中,通过方法传递变量的类型有不确定性.于是我们很难判断,一些操作是否可以运行. ...
- 【LeetCode 35】搜索插入位置
题目链接 [题解] 还是那句话,想知道l或者r所在的数字的含义 就想想它最后一次执行的时候在干什么就行. [代码] class Solution { public: int searchInsert( ...
- layui-treeTable v2.0添加搜索功能
layui-treeTable 添加搜索功能 在树形表格头部加一个input框: <div class="layui-inline"> <input class= ...
- php开发面试题---lavarel和tp的区别是什么(呕心整理)
php开发面试题---lavarel和tp的区别是什么(呕心整理) 一.总结 一句话总结: 反思的回顾非常有用,因为决定了我的方向和技巧 以战养己,这是非常非常好的方式 主要从大小.功能.安全性.操作 ...
- 测试技能图谱skill-map
# 测试技能图谱 ## 代码静态分析- Sonar- PMD- Infer- Android * findbugs * AndroidLint * CheckStyle- iOS * scanbuil ...