日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

Form与ModelForm中的插件使用

發(fā)布時(shí)間:2024/1/3 综合教程 31 生活家
生活随笔 收集整理的這篇文章主要介紹了 Form与ModelForm中的插件使用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、Form插件的使用

(一)widget參數(shù)

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="價(jià)格")  # 34.91
        pub_date = forms.DateField(label="日期",
            widget=widgets.TextInput(attrs={"type":"date"}) #插件
        )
        book_type=forms.ChoiceField(choices=((1,"自然科學(xué)"),(2,"社會(huì)學(xué)科"),(3,"其他")))
        publish=forms.ModelChoiceField(queryset=Publish.objects.all())
        authors=forms.ModelMultipleChoiceField(queryset=Author.objects.all())

在date字段中使用了插件,參數(shù)是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中接收插件參數(shù)為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__()

顯然,參數(shù)中傳入的是widgets.TextInput,所以進(jìn)入到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屬性。

(二)觸發(fā)widget渲染

渲染text.html,其實(shí)就是渲染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 %}

可是,在什么時(shí)候觸發(fā)渲染呢?

其實(shí)就是在渲染每一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聯(lián)系上了
    
    #調(diào)用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
        )

調(diào)用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標(biāo)簽渲染為:

<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":"價(jià)格"}
        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參數(shù),看看源碼中參數(shù)的定義:

#自定義ModelForm中Meta中的可傳參數(shù)
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) #插件參數(shù)
        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的元類中已經(jīng)生成了對應(yīng)fields,并且每個(gè)字段與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的流程了。





總結(jié)

以上是生活随笔為你收集整理的Form与ModelForm中的插件使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。