【问题标题】:Django Form: Calling foreign key field attributes in templateDjango Form:在模板中调用外键字段属性
【发布时间】:2021-03-20 21:56:31
【问题描述】:

在模板中,我想调用外键表单字段的类属性item.pid,如下所示

{%for item in form.item %}
{{item.pid}}
{% endfor %}

我的问题很简单,解决方案也应该如此,但我现在被困在这里太久了。我已经尝试过表单集、内联表单集、干净以及文档中和 SO 上的更多内容。 甚至不能调用表单域的类方法。

调用 {{form.instance.item.pid}} 应该是解决方案,但我无法让它运行。

model.py

class Event(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True, default=0)
    item = models.ForeignKey(Item, on_delete=models.CASCADE, blank=True, null=True, default=0)
#many more

class Person(models.Model):
    person_number = models.IntegerField(null=True)
    name = models.CharField(max_length=200, null=True)
    surname = models.CharField(max_length=200, null=True)
#many more

class Item(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True, default=0)
    pid = models.IntegerField(null=True) 
#many more

    def save(self, *args, **kwargs):  
        self.pid = Person.objects.filter(surname=self.person.surname, name=self.person.name).values("person_number")
        super(Item, self).save(*args, **kwargs) 

views.py

def event(request, event_id=None):

    if event_id:
        instance = get_object_or_404(Event, pk=event_id)
    else:
        instance = Event()
   
    form = EventForm(request.POST or None, instance=instance)    

    if request.POST and form.is_valid():
        form.save()
        return HttpResponseRedirect(reverse('cal:calendar'))
    context = {
        'form': form,
    }    
    return render(request, 'cal/event.html', context)

forms.py

class EventForm(ModelForm):
  class Meta:
    model = Event

    fields = ('person', 'item', 'manymore',)

【问题讨论】:

  • 显示该信息的目的是什么? Event 表单的 Item 字段(默认情况下)将允许您在不同的项目之间进行选择。但是,如果您愿意,您可以更改这些选择的呈现方式。
  • 我根据 item.pid 和 person.person_number 做出选择。例如创建一个链式下拉选择

标签: django forms foreign-keys class-attributes


【解决方案1】:

自定义 FK 字段的选择非常简单。

我在几个小时前已经完成了这项工作,并且我使用缓存方法完成了这项工作,这样每次都不会命中数据库来生成列表。

所以我有一个Currency 表,我希望允许申请人选择与其申请相关的货币;

class ApplicationForm(forms.ModelForm):
    """ Application form """

    currency = forms.ChoiceField(
        choices=[]
    )

    class Meta:
        """ Setup the form """
        fields = (
            ...
            'currency',
            ...
        )
        model = Application

    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields['currency'].choices = get_currency_choices()

    def clean(self):
        """
        Custom form cleaning
        """
        cleaned_data = super().clean()

        currency_id = cleaned_data.get('currency')
        cleaned_data['currency'] = Currency.objects.get(id=currency_id)

正如您在此表单中看到的,currency 字段正在从get_currency_choices 中获得它的选择。对于 ForeignKey,您还需要一个相关模型的实例来保存该关系,因此在 clean 中,我通过 ID 获取与选择相关的实例,ID 是表单中字段的值。

选择是从相关模型中生成的,并使用以下方法存储在缓存中;


def get_currency_choices():
    """ Get currency choices, from cache if possible """
    currency_choices = cache.get(CACHED_CURRENCY_KEY)
    if not currency_choices:
        currencies = Currency.objects.values('id', 'symbol', 'code')
        currency_choices = list()
        currency_choices.append((None, ''))  # I use this so that there isn't a default choice & people can't make the wrong choice by leaving the default value.
        for currency in currencies:
            currency_choices.append(
                (currency['id'], f"{currency['symbol']} ({currency['code']})")
            )
        cache.set(
            CACHED_CURRENCY_KEY, currency_choices, CACHED_CURRENCY_LENGTH
        )
    return currency_choices

【讨论】:

  • 非常感谢您抽出宝贵时间。实现了您的代码,我得到了两个结果:1. forms.py Meta 的定义就像我的示例中一样:代码运行但currency.id(我的案例:item.pid)什么都不返回。调用 item 很好并返回 __str__ 2. forms.py Meta 定义了你的返回方式:Exception Value: name 'get_item_choices' is not defined ...我尝试将 get_item_choices 放入 Event Class' 以及 Item Class ' 型号
  • 更新:我继续使用上面帖子中的 2. 并将方法直接放入__init__。附加的currency_choices现在显示在模板中。这让我想知道我尝试的所有解决方案是否都不起作用,因为我的forms.py 是错误的...... ps:附加不允许在代码中使用currency.id,对吗?
  • 如果您有get_item_choices is not defined,您只需在表单之前包含该函数,或从表单文件顶部的其他位置导入它。这样做将允许您将该字段包含为{{ form.item }},或者您希望显示该表单。你不需要迭代任何东西。只需确保您想要显示它的方式是由该选择功能生成的。
  • 我显然做错了什么。您的get_item_choices 以及以下解决方案正在运行,但我得到的只是__str__ 或最后一个字段,如doi。只要我添加*.pid 或*.doi,循环通过form.item 什么都不会返回。循环错误? test = forms.ChoiceField(choices=[]) | def __init__(self, *args, **kwargs): super(EventForm, self).__init__(*args, **kwargs) self.fields['test'].choices = list(Item.objects.values_list('pid', 'doi')) 或 test = forms.ModelChoiceField(queryset=Item.objects.all())
  • less blabla:通过代码在模板中循环返回f" ({tata['doi']})" 中的部分我的循环是{% for p in form.test %} {{p}}{% endfor %} 而{{p.pid}}什么都不做
猜你喜欢
  • 2021-01-24
  • 2019-07-31
  • 2016-04-18
  • 1970-01-01
  • 1970-01-01
  • 2011-01-06
  • 1970-01-01
  • 2018-11-18
  • 2020-04-25
相关资源
最近更新 更多