当前位置: 首页 > 面试题库 >

在Django模板中将CheckboxSelectMultiple分组

缑赤岩
2023-03-14
问题内容

如何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窗口小部件。通过使用代码段,我尝试通过将CheckboxSelectMultiplefield 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 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

然后在模板中:

{% 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 %}

结果:我在类别表中添加了国家名称,在功能表中添加了城市名称,因此在模板中,我能够根据国家(类别)对城市(功能)进行重新分组



 类似资料:
  • 我创建了新项目,但找不到出错的地方。 Django versiob - 3.1.5 蟒蛇 3.7.4 模板DoesNotExist位于/index。html请求方法:GET请求URL:http://127.0.0.1:8000/Django版本:3.1.5异常类型:TemplateDoesNotExist异常值: 索引。html异常位置:C:\Users\user\PycharmProjects\

  • 问题内容: 我对Django有一个奇怪的问题。我会像平时一样在模板中循环遍历一组对象。但是,我需要将项目分为三部分。页面的布局如下所示: 绘画1-绘画2-绘画3 描述1 描述2 描述3 绘画4-绘画-5绘画6 说明4 说明5 说明6 等 我不能弄清楚真正做到这一点的最好的Django标签集。似乎有些棘手。{%cycle%}语句并没有太大帮助。 除非当然,否则我会进行某种形式的Java脚本黑客攻击,

  • 问题内容: 我有一个模型字段,它存储一个URL列表(是的,我知道,这是错误的方式)。我需要将字段拆分为模板中的数组,因此创建了自定义过滤器: 我用这种方式: 但是正如我所看到的,split并不能正常工作:我得到类似的输出(如果查看源代码,则带有换行符)。为什么? 问题答案: Django有意排除了许多类型的templatetag,以阻止你对模板进行过多处理。(不幸的是,人们通常只是自己添加这些类型

  • 是时候把数据展示出来了!Django提供了一个非常有用的内置来实现-—|-模板标签 什幺是模板标签呢? 正如你在前面章节中所了解的那样, 我们并不能将 Python 代码嵌入到HTML中。 因为浏览器不能识别 Python 代码, 它只能解析HTML。 我们知道,HTML是静态页面,而 Python 则显得更加动态。 Django模板标签允许我们将Python之类的内容翻译成HTML,所以你可以更

  • 在上一章节中我们使用 django.http.HttpResponse() 来输出 "Hello World!"。该方式将数据与视图混合在一起,不符合 Django 的 MVC 思想。 本章节我们将为大家详细介绍 Django 模板的应用,模板是一个文本,用于分离文档的表现形式和内容。 模板应用实例 我们接着上一章节的项目将在 HelloWorld 目录底下创建 templates 目录并建立 h

  • 问题内容: 我正在寻找一种使用django中的模运算符之类的方法。我想做的是在循环中的每个第四个元素中添加一个类名。 使用模数,它看起来像这样: 当然,这是行不通的,因为%是保留字符。还有其他方法吗? 问题答案: 您需要divisibleby(内置的django过滤器)。