Как мне написать свой собственный виджет формы Django?

Может ли кто-нибудь привести простой пример, чтобы я понял основные идиомы того, как это делается? Я не могу найти никакой полезной документации, которую я могу понять по этой теме.

Чтобы обеспечить немного больше контекста, я хотел бы создать свои собственные переключатели, которые отображаются определенным образом.

Я просто ищу очень простой пример, который поможет мне понять эту концепцию.


person Jarrod    schedule 03.07.2016    source источник
comment
В этом вопросе есть комментарий, указывающий на: tothinkornottothink.com/post/10815277049/   -  person Nagaraj Tantri    schedule 03.07.2016


Ответы (1)


Трудно сказать, что вы подразумеваете под «очень простым примером». Вот очень простой пример:

from django.forms.widgets import Input

class TelInput(Input):
    input_type = 'tel'

Но я не думаю, что это вам сильно поможет.

Если вы ищете примеры, лучше всего проверить исходный код django. код.

Я думаю, этого должно быть достаточно, чтобы понять, как это работает:

from django.utils.encoding import force_text
from django.utils.html import format_html
from django.forms.utils import flatatt

class Widget(...):

    def __init__(self, attrs=None):
        if attrs is not None:
            self.attrs = attrs.copy()
        else:
            self.attrs = {}

    def subwidgets(self, name, value, attrs=None, choices=()):
        """
        Yields all "subwidgets" of this widget. Used only by RadioSelect to
        allow template access to individual <input type="radio"> buttons.
        Arguments are the same as for render().
        """
        yield SubWidget(self, name, value, attrs, choices)

    def render(self, name, value, attrs=None):
        """
        Returns this Widget rendered as HTML, as a Unicode string.
        The 'value' given is not guaranteed to be valid input, so subclass
        implementations should program defensively.
        """
        raise NotImplementedError('subclasses of Widget must provide a render() method')

    def build_attrs(self, extra_attrs=None, **kwargs):
        "Helper function for building an attribute dictionary."
        attrs = dict(self.attrs, **kwargs)
        if extra_attrs:
            attrs.update(extra_attrs)
        return attrs

    def value_from_datadict(self, data, files, name):
        """
        Given a dictionary of data and this widget's name, returns the value
        of this widget. Returns None if it's not provided.
        """
        return data.get(name)


class Input(Widget):
    """
    Base class for all <input> widgets (except type='checkbox' and
    type='radio', which are special).
    """
    input_type = None  # Subclasses must define this.

    def format_value(self, value):
        if self.is_localized:
            return formats.localize_input(value)
        return value

    def render(self, name, value, attrs=None):
        if value is None:
            value = ''
        final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
        if value != '':
            # Only add the 'value' attribute if a value is non-empty.
            final_attrs['value'] = force_text(self.format_value(value))
        return format_html('<input{} />', flatatt(final_attrs))

Наиболее важными методами являются render(), который отображает виджет в виде HTML-кода, и value_from_datadict(), который извлекает значение виджета из POST словаря данных.

person Antoine Pinsard    schedule 03.07.2016
comment
Обратите внимание, что HTML виджеты ДОЛЖНЫ иметь атрибут имени, иначе администратор Django не сможет прочитать их значения, и они будут просто исключены из отправки формы. - person Alan Porter; 05.08.2020
comment
@AlanPorter Этим занимается final_attrs = self.build_attrs(attrs, type=self.input_type, name=name). Имя определяется формой, а не самим виджетом. За кулисами Django передает имя поля методу render(). - person Antoine Pinsard; 06.08.2020
comment
Ах, да... Я не имел в виду, что этот пример пострадал от отсутствующего имени. Я работал с другим примером, найденным в блоге, и потратил два дня на его отладку. Я просто хотел, чтобы любой, кто идет по тому же пути, что и я, был осторожен, указывая имя. Спасибо, @Antoine-Pinsard! - person Alan Porter; 07.08.2020