使用多个选择元素的django formset中的动态模型选择字段

时间:2011-01-15 22:58:04

标签: django forms

我在django-users列表中发布了这个问题,但还没有回复。

我的模型看起来像这样:

class ProductGroup(models.Model):
     name = models.CharField(max_length=10, primary_key=True)
     def __unicode__(self): return self.name

class ProductRun(models.Model):
     date = models.DateField(primary_key=True)
     def __unicode__(self): return self.date.isoformat()

class CatalogItem(models.Model):
     cid     = models.CharField(max_length=25, primary_key=True)
     group   = models.ForeignKey(ProductGroup)
     run     = models.ForeignKey(ProductRun)
     pnumber = models.IntegerField()
     def __unicode__(self): return self.cid
     class Meta:
         unique_together = ('group', 'run', 'pnumber')

class Transaction(models.Model):
     timestamp   = models.DateTimeField()
     user        = models.ForeignKey(User)
     item        = models.ForeignKey(CatalogItem)
     quantity    = models.IntegerField()
     price       = models.FloatField()

假设大约有10个ProductGroups和10-20个相关产品 ProductRuns在任何给定时间。每组有20-200个不同 产品编号(pnumber),所以至少有几千个 CatalogItems。

我正在处理Transaction模型的formsets。代替 具有数千个CatalogItems的单选菜单 ForeignKey字段,我想替换三个下拉菜单 group,run和pnumber,唯一标识CatalogItem。 我还想限制后两个下拉菜单的选择 那些可用于当前的运行和pnumbers 选定的产品组(如果是用户,我可以通过AJAX更新它们 更改产品组,但初始页面很重要 如上所述加载而不依赖于AJAX)。

最好的方法是什么?

作为出发点,这是我到目前为止所尝试/考虑的内容:

我的第一种方法是从中排除项目外键字段 表单,通过覆盖add_fields添加替换下拉列表 formset的方法,然后提取数据并填充 在保存模型实例之前手动在模型实例上。它的 简单明了,但它并不是非常可重复使用的 不要认为这是正确的方法。

我的第二种方法是创建一个继承两者的新字段 MultiValueField和ModelChoiceField,以及一个对应的 MultiWidget子类。这似乎是正确的方法。如 Malcolm Tredinnick把它放进去了 a django-users discussion,  “一个领域的'智慧'在于Field类。”

我遇到的问题是何时/何地获取选择列表 来自db。我现在的代码在Field __init__中执行, 但这意味着我必须知道我正在处理哪个ProductGroup 在我甚至可以定义Form类之前,因为我必须实例化 我定义表单时的字段。所以我有一家工厂 从我的观点来看,我在最后一分钟打电话的功能 - 在我知道之后 我有什么CatalogItems以及他们所在的产品组 创建表单/表单集类并实例化它们。它有效,但我 想知道是否有更好的方法。毕竟,这个领域应该是 一旦知道,就能够在以后确定正确的选择 它的当前价值。

另一个问题是我的实现限制了整个formset 与(CatalogItems from)单一的交易 ProductGroup。

我很有趣的第三种可能性就是把它全部放在Widget中 类。一旦我有相关的模型实例,或cid,或 无论给出什么小部件,我都可以获得ProductGroup和 构建下拉列表。这将解决我的问题 第二种方法,但似乎不是正确的方法。

2 个答案:

答案 0 :(得分:3)

在formset中设置表单字段选择的一种方法是在表单 init 中覆盖self.fields [' field_name']。的选项,但是因为更多需要动态方法,这是在视图中有效的方法:

from django.forms.models import modelformset_factory
user_choices = [(1, 'something'), (2, 'something_else')]  # some basic choices
PurchaserChoiceFormSet = modelformset_factory(PurchaserChoice, form=PurchaserChoiceForm, extra=5, max_num=5)
my_formset = PurchaserChoiceFormSet(self.request.POST or None, queryset=worksheet_choices)

# and now for the magical for loop
for choice_form in my_formset:
    choice_form.fields['model'].choices = user_choices

我无法找到答案,但尝试了它,它适用于Django 1.6.5。我认为它是因为formsets和for循环似乎很好地结合在一起:))

答案 1 :(得分:0)

我最后坚持使用第二种方法,但我现在确信这是很长的短路。我不得不在ModelForm和FormField内部挖掘一下,IMO的复杂性超过了最小的好处。

我在关于第一种方法的问题中所写的内容,“这很简单,非常简单”应该是最好的。