Django: Как создать собственный виджет формы? - PullRequest
52 голосов
/ 16 января 2011

Мне сложно найти документацию о том, как написать собственный виджет.

Мои вопросы:

  • Если я создаю собственный виджет, можно ли его использовать аналогичным образом?для интерфейса администратора или для обычных форм?
  • Если я хочу разрешить пользователю редактировать список элементов, какой виджет я должен создать подкласс?Какие методы виджета мне нужно переопределить / реализовать?
  • Какой метод виджета отвечает за переход от ввода пользователя обратно к модели данных?

Спасибо.

Ответы [ 5 ]

47 голосов
/ 17 января 2011

Вы правы в том, что Django не предоставляет документацию по этой конкретной теме. Я советую вам взглянуть на встроенные виджеты в django.forms.widgets (я буду ссылаться на классы из этого модуля ниже).

Если я создаю собственный виджет, может ли он быть эквивалентно использован для интерфейса администратора или для обычных форм?

Администратор переопределяет некоторые виджеты (см. django.contrib.admin.options.FORMFIELD_FOR_DBFIELD_DEFAULTS). Возможно, вы можете создать подкласс ModelAdmin и изменить атрибут formfield_overrides, но я никогда ничего не делал с ModelAdmin, поэтому я не могу здесь помочь ...

Если я хочу разрешить пользователю редактировать список элементов, какой виджет я должен создать подкласс? Какие методы виджета мне нужно переопределить / реализовать?

Ваш виджет, вероятно, не имеет ничего общего с виджетами по умолчанию (с Select, если есть ?!). Подкласс от Widget, и если вы найдете какой-либо общий шаблон со встроенными функциями, вы все равно можете изменить его позже.

Реализуйте следующие методы:

  • render(self, name, value, attrs=None, renderer=None)

    Проверьте Input.render для простого примера. Он также поддерживает пользовательские атрибуты, которые включены в HTML. Вы также можете добавить атрибуты "id", см. MultipleHiddenInput.render о том, как это сделать. Не забудьте использовать mark_safe при выводе HTML напрямую. Если у вас довольно сложный виджет, вы можете использовать рендеринг шаблонов ( пример ).

  • _has_changed(self, initial, data)

    Дополнительно. Используется в admin для регистрации сообщений о том, что было изменено.

Какой метод виджета отвечает за переход от ввода пользователя обратно к модели данных?

Это не имеет ничего общего с виджетом - Джанго не может знать, какой виджет использовался в предыдущем запросе. Он может использовать только данные формы (POST), отправленные из формы. Таким образом, метод поля Field.to_python используется для преобразования ввода в тип данных Python (может вызвать ValidationError, если ввод неверен).

21 голосов
/ 03 марта 2017

Django <1.11 </h3> В дополнение к другим ответам это небольшой пример кода пользовательского виджета: widgets.py: from django.forms.widgets import Widget from django.template import loader from django.utils.safestring import mark_safe class MyWidget(Widget): template_name = 'myapp/my_widget.html' def get_context(self, name, value, attrs=None): return {'widget': { 'name': name, 'value': value, }} def render(self, name, value, attrs=None): context = self.get_context(name, value, attrs) template = loader.get_template(self.template_name).render(context) return mark_safe(template) my_widget.html: <textarea id="mywidget-{{ widget.name }}" name="{{ widget.name }}"> {% if widget.value %}{{ widget.value }}{% endif %}</textarea> Django 1.11

Виджеты теперь обрабатываются с использованием API визуализации форм .

5 голосов
/ 18 июля 2012

ПРИМЕЧАНИЕ: здесь есть три вопроса. Первые два вопроса см. В более полном ответе AndiDog. Я только отвечаю на третий вопрос здесь:

Q. Какой метод виджета отвечает за переход от ввода пользователя обратно к модели данных?

A. Метод value_from_datadict - это разновидность метода render виджета. Этот метод, вероятно, является тем, на что ссылаются документы Django на виджеты, когда он говорит: «Виджет обрабатывает рендеринг HTML и извлечение данных из словаря GET / POST, соответствующего виджету». В документации больше ничего нет по этому вопросу, но вы можете увидеть, как это работает, из кода для встроенных виджетов.

3 голосов
/ 09 декабря 2014

Обычно я начинаю с наследования от одного из существующих виджетов, добавляю новое требуемое свойство и затем изменяю метод рендеринга. Вот пример для фильтруемого виджета выбора, который я реализовал. Фильтрация осуществляется через jquery mobile.

class FilterableSelectWidget(forms.Select):
    def __init__(self, attrs=None, choices=()):
        super(FilterableSelectWidget, self).__init__(attrs, choices)
        # choices can be any iterable, but we may need to render this widget
        # multiple times. Thus, collapse it into a list so it can be consumed
        # more than once.
        self._data_filter = {}

    @property
    def data_filter(self):
        return self._data_filter

    @data_filter.setter
    def data_filter(self, attr_dict):
        self._data_filter.update(attr_dict)

    def render_option(self, selected_choices, option_value, option_label):
        option_value = force_text(option_value)
        if option_value in selected_choices:
            selected_html = mark_safe(' selected="selected"')
            if not self.allow_multiple_selected:
                # Only allow for a single selection.
                selected_choices.remove(option_value)
        else:
            selected_html = ''
        # use self.data_filter
        filtertext = self.data_filter.get(option_value)
        data_filtertext = 'data-filtertext="{filtertext}"'.\
            format(filtertext=filtertext) if filtertext else ''
        return format_html('<option value="{0}"{1} {3}>{2}</option>',
                           option_value,
                           selected_html,
                           force_text(option_label),
                           mark_safe(data_filtertext))

Затем в представлениях, где я создаю форму, я установлю data_filter для поля.

        some_form.fields["some_field"] = \
            forms.ChoiceField(choices=choices,
                              widget=FilterableSelectWidget)
        some_form.fields["some_field"].widget.data_filter = \
            data_filter
0 голосов
/ 10 марта 2015

Документация на сайте Django совсем не помогает.Это предложения по настройке виджетов, здесь , прервать использование form.as_p(), что затем ставит под угрозу значение форм, представленных в Django, то есть: сборку виджетов.Мне больше всего понравился floppyforms .Это облегчает определение виджетов с помощью шаблонов и является (почти) прозрачной заменой для собственного модуля форм Django.Он имеет отличную документацию и его легко подобрать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...