按类型在表单中对多个选项进行分组

时间:2012-03-22 14:44:33

标签: django django-models django-forms

我有一个Sandbox,其中包含大量由一个或多个组成的项目 更多属性。每个属性属于特定属性类型(例如颜色,形状等) 我不知道如何使用属性与属性类型一起呈现表单。

模型

class Sandbox(models.Model):
    item = models.ForeignKey('Item')

class Item(models.Model):
    name = models.CharField()
    sandbox = models.ForeignKey(Sandbox)
    attributes = models.ManyToManyField('Attribute')

class Attribute(models.Model):
    name = models.CharField()
    type = models.ForeignKey('AttributeType')

class AttributeType(models.Model):
    name = models.CharField()

class ItemAttribute(models.Model):
    # intermediary model to hold references
    item = models.ForeignKey(Item)
    type = models.ForeignKey(AttributeType)
    attribute = models.ForeignKey(Attribute)

的ModelForm

class Sandbox(ModelForm):
    class Meta:
        model = Sandbox

每种属性类型只能有一个选项。例如,某些东西只能有一种颜色 或一个形状。

    AttributeType   Attribute       Users choice
    color
                    red
                    blue            [x]
                    green
                    shape

    shape
                    triangular
                    squared         [x]
                    spherical

这是我被困住了。如何在表单中将这些属性组合在一起,如何使用单选按钮为每种类型仅选择一个属性? 也许我最初的想法是简单的模型表示在这里不足? 我已经尝试过文档,StackOverflow和谷歌,但没有运气。

欢迎任何提示和想法。

我的解决方案

我建立了满足我需求的解决方案。 @bmihelac向我指出了如何创建工厂方法来创建自定义表单的方向。 [见下文]

def make_sandbox_form(item):

    def get_attributes(item):
        item_attributes = ItemAttribute.objects.filter(item=item)
        # we want the first attribute type
        _attr_type = item_attributes[0].attribute.all()[0].attribute_type

        choices = []        # holds the final choices
        attr_fields = {}    # to hold the final list of fields
        for item_attrs in item_attributes.all():
            attributes = item_attrs.attribute.all().order_by('attribute_type')
            for attr in attributes:
                print attr.attribute_type, ' - ' , _attr_type
                if attr.attribute_type == _attr_type:
                    choices.append( ( attr.pk, attr.value ) )
                else:
                    d = {u'%s' % _attr_type : fields.ChoiceField(choices=choices, widget=RadioSelect)}
                    attr_fields = dict(attr_fields.items() + d.items() )
                    # set the _attr_type to new type and start over with next attribute type
                    _attr_type = attr.attribute_type
                    choices = []

        return attr_fields

    form_fields = {
        'item' : fields.IntegerField(widget=HiddenInput),
    }
    form_fields = dict(form_fields.items() + get_attributes(item).items())

    return type('SandboxForm', (forms.BaseForm, ), { 'base_fields' : form_fields})

调用我的调用此工厂方法的表单: form = make_sandbox_form()

http://www.b-list.org/weblog/2008/nov/09/dynamic-forms/

(希望除了作为StackOverflow的新手之外,我还可以投票,但我没有这么做的声誉。)

2 个答案:

答案 0 :(得分:1)

一个沙箱可以有多个项目,或者一个项目有多个沙箱?一个项目可以同时属于多个沙箱吗?

我认为您希望一个沙箱包含许多项目:

class Sandbox(models.Model):
    name = models.CharField()

class Item(models.Model):
    name = models.CharField()
    sandbox= models.ForeignKey(Sandbox)
    attributes = models.ManyToManyField('Attribute')

同样的分析也适用于此:

一个属性是否有许多属性类型,或者一个属性类型有多个属性?

在这里你有正确的关系,我只是改变了模型的顺序

class AttributeType(models.Model):
    name = models.CharField()

class Attribute(models.Model):
    name = models.CharField()
    type = models.ForeignKey(AttributeType)

因此每个项目都有一个属性,它们总是被赋予这些属性,颜色和形状。

虽然您可以拥有一个包含以下数据的表:

pk type
1 green
2 circular
etc

我个人不会这样做,因为我认为逻辑上相同的数据应该组合在一起。形状与颜色具有不同的属性。例如,为了说明我的观点,如果你想要一种颜色的RGB怎么办?然后,当不需要时,你会有额外的形状列,这是令人困惑的。反过来也是如此,颜色没有尺寸。

相反,我可能会这样做:

class Color(models.Mode):
     #info about colors

class Shape(models.Mode):
     #info about shapes

class Item(models.Model):
    name = models.CharField()
    sandbox= models.ForeignKey(Sandbox)
    color= models.ForeignKey(Color)
    shape= models.ForeignKey(Shape)

这也保证每个只有一个选项,因为django.Forms中的ForeignKey默认为ChioceField(iirc)。

至于覆盖它并使其成为无线电按钮,只需查看文档:

https://docs.djangoproject.com/en/dev/ref/forms/widgets/

答案 1 :(得分:1)

我会创建动态表单,为每个AttributeType创建一个选择字段。

然后,您可以使用单选按钮轻松替换小部件。

本文可能会有所帮助:

http://www.b-list.org/weblog/2008/nov/09/dynamic-forms/