- <select name="school_user-0-year_start_year" id="id_school_user-0-year_start">
- </select>
Инициализация виджета (class Widget)
- def __init__(self, attrs=None):
- if attrs is not None:
- self.attrs = attrs.copy()
- else:
- self.attrs = {}
Возьмем для примера следующий виджет:
- class Select(Widget):
- def __init__(self, attrs=None, choices=()):
- super(Select, self).__init__(attrs)
В принципе понятно, что происходит. Далее, рассмотрим функцию рендеринга виджета:
- def render(self, name, value, attrs=None, choices=()):
- if value is None: value = ''
- final_attrs = self.build_attrs(attrs, name=name)
- output = [u'<select%s>' % flatatt(final_attrs)]
- options = self.render_options(choices, [value])
- if options:
- output.append(options)
- output.append('')
- return mark_safe(u'\n'.join(output))
- ct%s>
Что делает функция build_attrs?
- 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
Функция принимает **kwargs (keyworded аргументы, то есть аргументы с ключами), в нашем случае передается ключ name с названием данного виджета. В итоге мы получаем примерно следующее:
- <select name="school_user-0-year_start_year">
- </select>
Но откуда берется id?
Оно приходит в атрибутах до рендеренга виджета, из далеких глубин класса class BoundField(StrAndUnicode), который описан в исходниках как "A Field plus data".
Функция класса as_widget собственно и инициирует вызов рендеринга виджета.
- def as_widget(self, widget=None, attrs=None, only_initial=False):
- """
- Renders the field by rendering the passed widget, adding any HTML
- attributes passed as attrs. If no widget is specified, then the
- field's default widget will be used.
- """
- if not widget:
- widget = self.field.widget
- attrs = attrs or {}
- auto_id = self.auto_id
- if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
- attrs['id'] = auto_id
- if not self.form.is_bound:
- data = self.form.initial.get(self.name, self.field.initial)
- if callable(data):
- data = data()
- else:
- data = self.data
- if not only_initial:
- name = self.html_name
- else:
- name = self.html_initial_name
- return widget.render(name, data, attrs=attrs)
Поэтому, добавить свои атрибуты или получить данные из словаря в процессе переопределения рендеринга не сложно.
- class MyWidget(forms.Select):
- def render(self, name, value, attrs=None, choices=()):
- id_ = attrs.get('id', None)
- attrs.update({'onchange':'javascriptfunction(%s%s);' % id_,name})
- return super(MyWidget, self).render(name, value, attrs)
Хотя можно передавать атрибуты и в определении самого виджета, функция self.build_attrs() просто обновит словарь новыми записями, но мне надо было именно переопределить атрибуты в виджете, для создания мультивиджета.
attrs.update() в мультивиджетах меняет атрибуты во всех подвиджетах.
Блоггер почемуто br-ки понавставлял, баг какой-то, что-то не нашел как его лечить..
ОтветитьУдалить