加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

Django模板中的Grouped CheckboxSelectMultiple

发布时间:2020-12-20 10:32:00 所属栏目:Python 来源:网络整理
导读:如何通过相关模型对CheckboxSelectMultiple生成的复选框进行分组? 最好通过示例来说明这一点. models.py: class FeatureCategory(models.Model): name = models.CharField(max_length=30)class Feature(models.Model): name = models.CharField(max_length
如何通过相关模型对CheckboxSelectMultiple生成的复选框进行分组?

最好通过示例来说明这一点.

models.py:

class FeatureCategory(models.Model):
    name = models.CharField(max_length=30)

class Feature(models.Model):
    name = models.CharField(max_length=30)
    category = models.ForeignKey(FeatureCategory)

class Widget(models.Model):
    name = models.CharField(max_length=30)
    features = models.ManyToManyField(Feature,blank=True)

forms.py:

class WidgetForm(forms.ModelForm):
    features = forms.ModelMultipleChoiceField(
        queryset=Feature.objects.all(),widget=forms.CheckboxSelectMultiple,required=False
    )
    class Meta:
        model = Widget

views.py:

def edit_widget(request):
    form = WidgetForm()
    return render(request,'template.html',{'form': form})

template.html:

{{ form.as_p }}

以上产生以下输出:

[] Widget 1
[] Widget 2
[] Widget 3
[] Widget 1
[] Widget 2

我想要的是功能复选框按功能类别分组(基于ForeignKey):

Category 1:
  [] Widget 1
  [] Widget 2
  [] Widget 3

Category 2:
  [] Widget 1
  [] Widget 2

我怎样才能做到这一点?我尝试使用{%regroup%}模板标签无效.

任何建议都非常感谢.

谢谢.

解决方法

您必须编写自定义CheckboxSelectMultiple小部件.使用 snippet我尝试通过在field attrs中添加category_name作为属性来使CheckboxSelectMultiple字段可迭代.这样我以后就可以在模板中使用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 CheckboxInput(SubWidget):
    """
    An object used by CheckboxRenderer that represents a single
    <input type='checkbox'>.
    """
    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='checkbox',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 CheckboxRenderer(StrAndUnicode):
    def __init__(self,choices):
        self.name,self.value,self.attrs = name,attrs
        self.choices = choices

    def __iter__(self):
        for i,choice in enumerate(self.choices):
            yield CheckboxInput(self.name,self.attrs.copy(),i)

    def __getitem__(self,idx):
        choice = self.choices[idx] # Let the IndexError propogate
        return CheckboxInput(self.name,idx)

    def __unicode__(self):
        return self.render()

    def render(self):
        """Outputs a <ul> for this set of checkbox fields."""
        return mark_safe(u'<ul>n%sn</ul>' % u'n'.join([u'<li>%s</li>'
                % force_unicode(w) for w in self]))

class CheckboxSelectMultipleIter(forms.CheckboxSelectMultiple):
    """
    Checkbox multi select field that enables iteration of each checkbox
    Similar to django.forms.widgets.RadioSelect
    """
    renderer = CheckboxRenderer

    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(CheckboxSelectMultipleIter,self).__init__(*args,**kwargs)

    def subwidgets(self,choices=()):
        for widget in self.get_renderer(name,choices):
            yield widget

    def get_renderer(self,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,choices=()):
        return self.get_renderer(name,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=CheckboxSelectMultipleIter,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 %}

结果:我在类别表中添加了国家/地区名称,并在功能表中添加了城市名称,因此在模板中我能够根据国家(类别)重新组合城市(功能)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读