你必须编写自定义Check@R_9_2419@SelectMultiple
窗口小部件。通过使用代码段,我尝试通过将Check@R_9_2419@SelectMultiplefield category_name
作为属性添加到字段中以使字段可迭代attrs
。这样我以后可以regroup
在模板中使用标记。
下面的代码根据你的需要从代码段中进行了修改,显然可以使此代码更简洁,更通用,但是目前还不是通用的。
forms.py
from django import forms
from django.forms import Widget
from django.forms.widgets import SubWidget
from django.forms.util import flatatt
from django.utils.html import conditional_escape
from django.utils.encoding import StrAndUnicode, force_unicode
from django.utils.safestring import mark_safe
from itertools import chain
import ast
from mysite.models import Widget as wid # your model name is conflicted with django.forms.Widget
from mysite.models import Feature
class Check@R_9_2419@Input(SubWidget):
"""
An object used by Check@R_9_2419@Renderer that represents a single
<input type='check@R_9_2419@'>.
"""
def __init__(self, name, value, attrs, choice, index):
self.name, self.value = name, value
self.attrs = attrs
self.choice_value = force_unicode(choice[1])
self.choice_label = force_unicode(choice[2])
self.attrs.update({'cat_name': choice[0]})
self.index = index
def __unicode__(self):
return self.render()
def render(self, name=None, value=None, attrs=None, choices=()):
name = name or self.name
value = value or self.value
attrs = attrs or self.attrs
if 'id' in self.attrs:
label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
else:
label_for = ''
choice_label = conditional_escape(force_unicode(self.choice_label))
return mark_safe(u'<label%s>%s %s</label>' % (label_for, self.tag(), choice_label))
def is_checked(self):
return self.choice_value in self.value
def tag(self):
if 'id' in self.attrs:
self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index)
final_attrs = dict(self.attrs, type='check@R_9_2419@', name=self.name, value=self.choice_value)
if self.is_checked():
final_attrs['checked'] = 'checked'
return mark_safe(u'<input%s />' % flatatt(final_attrs))
class Check@R_9_2419@Renderer(StrAndUnicode):
def __init__(self, name, value, attrs, choices):
self.name, self.value, self.attrs = name, value, attrs
self.choices = choices
def __iter__(self):
for i, choice in enumerate(self.choices):
yield Check@R_9_2419@Input(self.name, self.value, self.attrs.copy(), choice, i)
def __getitem__(self, idx):
choice = self.choices[idx] # Let the IndexError propogate
return Check@R_9_2419@Input(self.name, self.value, self.attrs.copy(), choice, idx)
def __unicode__(self):
return self.render()
def render(self):
"""Outputs a <ul> for this set of check@R_9_2419@ fields."""
return mark_safe(u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>'
% force_unicode(w) for w in self]))
class Check@R_9_2419@SelectMultipleIter(forms.Check@R_9_2419@SelectMultiple):
"""
Check@R_9_2419@ multi select field that enables iteration of each check@R_9_2419@
Similar to django.forms.widgets.RadioSelect
"""
renderer = Check@R_9_2419@Renderer
def __init__(self, *args, **kwargs):
# Override the default renderer if we were passed one.
renderer = kwargs.pop('renderer', None)
if renderer:
self.renderer = renderer
super(Check@R_9_2419@SelectMultipleIter, self).__init__(*args, **kwargs)
def subwidgets(self, name, value, attrs=None, choices=()):
for widget in self.get_renderer(name, value, attrs, choices):
yield widget
def get_renderer(self, name, value, attrs=None, choices=()):
"""Returns an instance of the renderer."""
choices_ = [ast.literal_eval(i[1]).iteritems() for i in self.choices]
choices_ = [(a[1], b[1], c[1]) for a, b, c in choices_]
if value is None: value = ''
str_values = set([force_unicode(v) for v in value]) # Normalize to string.
if attrs is None:
attrs = {}
if 'id' not in attrs:
attrs['id'] = name
final_attrs = self.build_attrs(attrs)
choices = list(chain(choices_, choices))
return self.renderer(name, str_values, final_attrs, choices)
def render(self, name, value, attrs=None, choices=()):
return self.get_renderer(name, value, attrs, choices).render()
def id_for_label(self, id_):
if id_:
id_ += '_0'
return id_
class WidgetForm(forms.ModelForm):
features = forms.ModelMultipleChoiceField(
queryset=Feature.objects.all().values('id', 'name', 'category__name'),
widget=Check@R_9_2419@SelectMultipleIter,
required=False
)
class Meta:
model = wid
然后在模板中:
{% for field in form %}
{% if field.name == 'features' %}
{% regroup field by attrs.cat_name as list %}
<ul>
{% for el in list %}
<li>{{el.grouper}}
<ul>
{% for e in el.list %}
{{e}} <br />
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
{% else %}
{{field.label}}: {{field}}
{% endif %}
{% endfor %}
结果:我在类别表中添加了国家名称,在功能表中添加了城市名称,因此在模板中,我能够根据国家(类别)对城市(功能)进行重新分组