【问题标题】:Django: Accessing model fields from form widget in templateDjango:从模板中的表单小部件访问模型字段
【发布时间】:2018-07-18 18:09:20
【问题描述】:

我有一个 ModelForm,它使用 CheckboxSelectMultiple 小部件来表示来自 ManyToManyField 的数据。默认情况下,这将呈现一个复选框列表,其标签设置为相关模型的__str__ 方法的返回值。但是,除了小部件提供的choice_label 之外,我希望显示来自相关模型中其他字段的数据。例如考虑下面的实现:

models.py

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name

class Item(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)

    def __str__(self):
        return self.name

class Order(models.Model):
    items = models.ManyToManyField('Item')

forms.py

from django import forms
from .models import Order

class OrderForm(forms.ModelForm):
    class Meta:
        model = Order
        fields = ['items']
        widgets = {'items': forms.widgets.CheckboxSelectMultiple}

模板.html

{% for item in form.items %}
    <tr>
        <td>{{ item.tag }}</td>
        <td>{{ item.choice_label }}</td>
        <td>{{ item.category }}</td>
    </tr>
{% endfor %}

这里的问题是 template.html 的 {{ item.category }} 部分。当使用{% for item in form.items %} 循环遍历所有项目复选框时,item 的类型为BoundWidget,而不是Item。这就是提供tagchoice_label 属性来呈现表单复选框的原因。我的问题是BoundWidget 似乎没有对复选框所代表的Item 实例的任何引用,这将允许我访问任何其他模型数据,例如项目所在的类别。有没有解决办法?

编辑:

我能想到的唯一方法是:

模板标签/app_tags.py

from django import template
from models import Item

register = template.Library()

@register.inclusion_tag('app/order_item_table.html')
def show_item_table(items):
    item_objs = []
    for item in items:
        id = item.data['value']
        obj = Item.objects.get(id=id)
        item_objs.append((item, obj))
    return {'items': item_objs}

order_item_template.html

{% for item, obj in items %}
    <tr>
        <td>{{ item.tag }}</td>
        <td>{{ item.choice_label }}</td>
        <td>{{ obj.category }}</td>
    </tr>
{% endfor %}

模板.html

{% load app_tags %}

{% show_item_table form.items %}

但这似乎令人难以置信,我真的很想知道是否有更好的方法来做到这一点?

【问题讨论】:

  • 这有什么更新吗?我遇到了同样的问题。我正在考虑访问小部件中的查询集,但我不知道如何

标签: python django django-forms django-templates


【解决方案1】:

我找到了一个 sliglty 不同的解决方案(我不得不重新实现一个小部件以供自己使用)

我已经为一个新的小部件创建了一个类(我也必须更改渲染,在你的情况下,get_context ovverridign 可能就足够了)

class MyWidget(forms.widgets.CheckboxSelectMultiple):
    template_name = 'web_admin/partial/checkbox.html'
    qs = None

    def get_context(self, name, value, attrs):
        ctx = super().get_context(name, value, attrs)
        ctx.update(dict(qs=self.qs))
        return ctx

注意get_context 如何使用self.qs 更新上下文

现在,在form

class MyForm(ModelForm):
    class Meta:
        model = MyModel
        fields = ['my_field']
        widgets = {
            'my_field': MyWidget,

        }

    def __init__(self, qs, *args, **kwargs):
        # this is set in get_form_kwargs of the view
        super().__init__(*args, **kwargs)
        self.fields['my_field'].queryset = qs
        self.fields['data_controller'].widget.qs = qs

self.fields['my_field'].queryset = qs我需要它来过滤可能的选项,你需要的是self.fields['data_controller'].widget.qs = qs

在视图中(我使用基于类的视图)

class ConsentCreationDC(CreateView):
    template_name = "web_admin/consent_creation_new.html"
    form_class = MyForm

    def get_form_kwargs(self):
        ctx = super().get_form_kwargs()
        ctx.update({'qs': THE_QUERY_SET})
        return ctx

现在在小部件模板(html 文件)中,您可以访问 qs 对象

我在过滤器所在的地方做了{% with obj_item=qs|index:widget.index %}

@register.filter def index(List, i): return List[int(i)]

在你的情况下应该是{% with obj_item=qs|index:item.index %}(不确定项目是否有index

希望对你有所帮助

【讨论】:

猜你喜欢
  • 2013-03-16
  • 2011-03-13
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 2012-06-05
  • 2012-11-08
相关资源
最近更新 更多