Интересный вопрос, и я думаю, возможно, заслуживает немного большего внимания в документах.
Вот пример из вопроса, который я только что задал :
class DateSelectorWidget(widgets.MultiWidget):
def __init__(self, attrs=None, dt=None, mode=0):
if dt is not None:
self.datepos = dt
else:
self.datepos = date.today()
# bits of python to create days, months, years
# example below, the rest snipped for neatness.
years = [(year, year) for year in year_digits]
_widgets = (
widgets.Select(attrs=attrs, choices=days),
widgets.Select(attrs=attrs, choices=months),
widgets.Select(attrs=attrs, choices=years),
)
super(DateSelectorWidget, self).__init__(_widgets, attrs)
def decompress(self, value):
if value:
return [value.day, value.month, value.year]
return [None, None, None]
def format_output(self, rendered_widgets):
return u''.join(rendered_widgets)
Что я наделал?
- в подклассе
django.forms.widgets.MultiWidget
- Реализован конструктор, который создает несколько
widgets.WidgetName
виджетов в
кортеж. Это важно, потому что суперкласс использует существование этого кортежа, чтобы позаботиться о нескольких вещах для вас.
- Мой вывод в формате является сквозным, но идея в том, что вы можете добавить сюда собственный HTML, если хотите
- Я также реализовал
decompress
, потому что вы должны - вы должны ожидать передачи значений из базы данных в одном value
объекте. decompress
разбивает это для отображения в виджете. Как и что вы здесь делаете, зависит от вас и зависит от виджета.
Вещи, которые я не имел, но мог бы переопределить:
render
, это фактически отвечает за рендеринг виджетов, поэтому вам определенно нужно вызвать метод супер рендеринга, если вы подкласс это. Вы можете изменить способ отображения вещей непосредственно перед рендерингом, подклассами этого.
Пример, метод рендеринга django markitup :
def render(self, name, value, attrs=None):
html = super(MarkItUpWidget, self).render(name, value, attrs)
if self.auto_preview:
auto_preview = "$('a[title=\"Preview\"]').trigger('mouseup');"
else: auto_preview = ''
html += ('<script type="text/javascript">'
'(function($) { '
'$(document).ready(function() {'
' $("#%(id)s").markItUp(mySettings);'
' %(auto_preview)s '
'});'
'})(jQuery);'
'</script>' % {'id': attrs['id'],
'auto_preview': auto_preview })
return mark_safe(html)
value_from_datadict
- см. Мой вопрос здесь . value_from_datadict извлекает значение, связанное с этим виджетом, из словаря данных всех представленных данных с помощью этой формы. В случае мультивиджета, представляющего одно поле, вам необходимо восстановить это значение из нескольких подвиджетов, как данные будут представлены.
_get_media
может быть полезно для вас, если вы хотите извлекать мультимедиа, используя представление медиафайлов django. Реализация по умолчанию циклически изменяет виджеты, запрашивая медиа; если вы создаете подкласс и используете модные виджеты, вам нужно вызвать super; если вашему виджету нужен какой-либо носитель, то вам нужно добавить его, используя это.
Например, markitup виджет django делает это:
def _media(self):
return forms.Media(
css= {'screen': (posixpath.join(self.miu_skin, 'style.css'),
posixpath.join(self.miu_set, 'style.css'))},
js=(settings.JQUERY_URL,
absolute_url('markitup/jquery.markitup.js'),
posixpath.join(self.miu_set, 'set.js')))
media = property(_media)
Опять же, он создает кортеж путей к правильному местоположению, так же, как мой виджет создал кортеж виджетов в методе __init__
.
Я думаю, что это охватывает важные части класса MultiWidget
. То, что вы пытаетесь сделать, зависит от того, что вы создали / какие виджеты вы используете, поэтому я не могу вдаваться в подробности. Однако, если вы хотите увидеть базовый класс для себя и взглянуть на комментарии, взгляните на источник .