Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django模板中的分组复选框SelectMultiple_Django_Django Forms_Django Templates - Fatal编程技术网

Django模板中的分组复选框SelectMultiple

Django模板中的分组复选框SelectMultiple,django,django-forms,django-templates,Django,Django Forms,Django Templates,如何对相关型号的复选框selectmultiple生成的复选框进行分组 这最好用例子来说明 型号。py: class FeatureCategory(models.Model): name = models.CharField(max_length=30) class Feature(models.Model): name = models.CharField(max_length=30) category = models.ForeignKey(FeatureCate

如何对相关型号的
复选框selectmultiple
生成的复选框进行分组

这最好用例子来说明

型号。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)
class WidgetForm(forms.ModelForm):
    features = forms.ModelMultipleChoiceField(
        queryset=Feature.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False
    )
    class Meta:
        model = Widget
def edit_widget(request):
    form = WidgetForm()
    return render(request, 'template.html', {'form': form})
{{ form.as_p }}
forms.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)
class WidgetForm(forms.ModelForm):
    features = forms.ModelMultipleChoiceField(
        queryset=Feature.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False
    )
    class Meta:
        model = Widget
def edit_widget(request):
    form = WidgetForm()
    return render(request, 'template.html', {'form': form})
{{ form.as_p }}
视图。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)
class WidgetForm(forms.ModelForm):
    features = forms.ModelMultipleChoiceField(
        queryset=Feature.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False
    )
    class Meta:
        model = Widget
def edit_widget(request):
    form = WidgetForm()
    return render(request, 'template.html', {'form': form})
{{ form.as_p }}
template.html:

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)
class WidgetForm(forms.ModelForm):
    features = forms.ModelMultipleChoiceField(
        queryset=Feature.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        required=False
    )
    class Meta:
        model = Widget
def edit_widget(request):
    form = WidgetForm()
    return render(request, 'template.html', {'form': form})
{{ form.as_p }}
上述操作产生以下输出:

[] Widget 1
[] Widget 2
[] Widget 3
[] Widget 1
[] Widget 2
我希望功能复选框按功能类别分组(基于
ForeignKey
):

我怎样才能做到这一点?我尝试使用
{%regroup%}
模板标记,但没有效果

非常感谢您的建议


谢谢。

您必须编写自定义的
复选框selectmultiple
小部件。使用我已尝试通过在字段
attrs
中添加
category\u name
作为属性,使
复选框selectmultiple
字段可编辑。这样我以后就可以在模板中使用
重组
标记了

下面的代码是根据您的需要从snippet中修改而来的,很明显,这段代码可以变得更干净、更通用,但目前它还不是通用的

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, 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 CheckboxInput(self.name, self.value, self.attrs.copy(), choice, i)

    def __getitem__(self, idx):
        choice = self.choices[idx] # Let the IndexError propogate
        return CheckboxInput(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 checkbox 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 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, 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=CheckboxSelectMultipleIter,
        required=False
    )
    class Meta:
        model = wid
来自django导入表单的

从django.forms导入小部件
从django.forms.widgets导入子widget
从django.forms.util导入flatatt
从django.utils.html导入条件转义
从django.utils.encoding导入StrAndUnicode,强制使用unicode
从django.utils.safestring导入标记_safe
来自itertools进口链
导入ast
从mysite.models导入Widget作为wid#您的模型名称与django.forms.Widget冲突
从mysite.models导入功能
类CheckboxInput(子小部件):
"""
CheckboxRenderer使用的对象,表示单个
.
"""
定义初始化(自我、名称、值、属性、选项、索引):
self.name,self.value=名称,值
self.attrs=attrs
self.choice\u value=force\u unicode(选项[1])
self.choice\u label=force\u unicode(选项[2])
self.attrs.update({'cat_name':选项[0]})
self.index=索引
def ___; unicode(自):
返回self.render()
def render(self,name=None,value=None,attrs=None,choices=()):
name=name或self.name
value=value或self.value
attrs=attrs或self.attrs
如果self.attrs中的“id”:
label_for='for=“%s_u%s”%”(self.attrs['id'],self.index)
其他:
标签_为=“”
choice\u label=条件转义(强制unicode(self.choice\u label))
返回mark_safe(u“%s%s%”(label_for,self.tag(),choice_label))
def已检查(自):
在self.value中返回self.choice\u值
def标签(自我):
如果self.attrs中的“id”:
self.attrs['id']='%s\u%s%.(self.attrs['id'],self.index)
final\u attrs=dict(self.attrs,type='checkbox',name=self.name,value=self.choice\u value)
如果选中了self.u():
最终属性['checked']='checked'
返回标记安全(u''%flatatt(最终属性))
类CheckboxRenderer(StrAndUnicode):
定义初始化(自我、名称、值、属性、选项):
self.name,self.value,self.attrs=名称,值,attrs
自我选择
定义(自我):
对于i,枚举中的选择(self.choices):
yield CheckboxInput(self.name、self.value、self.attrs.copy()、choice、i)
def uu getitem uu(self,idx):
choice=self.choices[idx]#让索引器传播
返回CheckboxInput(self.name、self.value、self.attrs.copy()、choice、idx)
def ___; unicode(自):
返回self.render()
def渲染(自):
“”“为此复选框字段集输出一个
    。”“” 返回标记\u safe(u'
      \n%s\n
    '%u'\n'。加入([u'
  • %s
  • ' %强制_unicode(w)表示w(在self中)() 类CheckboxSelectMultipleIter(forms.CheckboxSelectMultiple): """ 复选框多选字段,用于启用每个复选框的迭代 类似于django.forms.widgets.RadioSelect """ 渲染器=复选框渲染器 定义初始化(self,*args,**kwargs): #如果传递了一个渲染器,则重写默认渲染器。 renderer=kwargs.pop('renderer',无) 如果渲染器: self.renderer=渲染器 超级(复选框SelectMultipleIter,self)。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu初始(*参数,**kwargs) def子部件(self、name、value、attrs=None、choices=()): 对于self.get_呈现程序中的小部件(名称、值、属性、选项): 收益小部件 def get_渲染器(self、name、value、attrs=None、choices=()): “”“返回渲染器的实例。”“” choices_u=[ast.literal_eval(i[1]).iteritems()表示self.choices中的i] 选项【(a[1],b[1],c[1]),用于选项【】中的a,b,c 如果值为无:值=“” str_values=set([force_unicode(v)for v in value])#规范化为字符串。 如果attrs为None: 属性={} 如果属性中没有“id”: 属性['id']=名称 最终属性=自生成属性(属性) 选项=列表(链(选项,选项)) 返回self.renderer(名称、str\u值、最终属性、选项) def render(self、name、value、attrs=None、choices=()): 返回self.get_呈现器(名称、值、属性、选项).render() def id_用于_标签(self,id_u): 如果id u3;: id_U0+='0' 返回id_ 类WidgetForm(forms.ModelForm): features=forms.ModelMultipleChiceField( queryset=Feature.objects.all().values('id','name','category__name'), widget=CheckboxSelectMultipleIter, 必需=错误 ) 类元: 型号=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 %}
{% regroup form.features by data.group as feature_list %}
{% for group in feature_list %}
<h6>{{ group.grouper|default:"Other Features" }}</h6>
<ul>
  {% for choice in group.list %}
  <li>{{ choice }}</li>
  {% endfor %}
</ul>
</div>
{% endfor %}
{%用于表单%]中的字段
{%if field.name='功能“%”
{%按attrs.cat_名称将字段重新组合为列表%}
    {列表%中el的百分比为%1}
  • {{el.gropper}}
      {el.list%中的e为%1} {{e}}
      {%endfor%}
  • {%endfor