【问题标题】:Grouping many to many choices by type in form在表单中按类型对多对多选择进行分组
【发布时间】:2012-03-22 14:44:32
【问题描述】:

我有一个沙盒,其中包含大量由一个或 更多属性。每个属性都属于特定的属性类型(例如颜色、形状等) 我不知道如何使用与它们的 AttributeTypes 分组在一起的属性来呈现表单。

型号

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)

模型表单

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

每个属性类型只能有一个选择。例如,某物只能有一种颜色 或一种形状。

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

    shape
                    triangular
                    squared         [x]
                    spherical

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

欢迎任何提示和想法。

我的解决方案

我建立了一个满足我需求的解决方案。 @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 新秀之外的所有人都可以投票,但我没有这样做的声誉。)

【问题讨论】:

  • 你看过regroup模板标签(允许你按属性分组)
  • 是的,我做到了,但我找不到使用表单实现它的方法,只能使用查询集。我在想的是,这个问题可以通过制作一个新的表单渲染方法来解决......问题是如何......

标签: django django-models django-forms


【解决方案1】:

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

然后,您可以轻松地将小部​​件替换为单选按钮。

这篇文章可能会有所帮助:

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

【讨论】:

    【解决方案2】:

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

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

    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/

    【讨论】:

    • 是的,你敏锐的眼睛注意到我错过了从 Item 到 Sandbox 的引用。更新了我的问题。谢谢!关键是在这种情况下,我无法为每种类型创建单独的模型,因为它们将由用户通过管理界面添加。 AttributeType 的数量可以超出我最初的想法。
    • @droidballoon 您仍然可以将它们分开并将数据输入推送给用户。如果一种颜色不存在,只需给他们一个创建新颜色/形状的选项。
    • 确实,我的意思是,如果用户想要创建一个新的 AttributeType,比如“声音”,那么开发人员必须为此 AttributeType 创建一个新模型以适应更改。还是我错过了什么?
    • @droidballoon 是的,但这通常不是一件难事。在 postgres 和大多数其他数据库实现中,添加一个新列(在本例中为 item)是相当容易的。这并不是说您不能按照您最初建议的方式进行操作,您当然可以,但是如果您想要有关该类型的其他信息怎么办?比如,那种声音、震动、嘎嘎声等?您最终会得到很多对属性类型没有意义的列。如果您永远不需要进一步定义属性类型,那么使用您的原始方法可能不是问题。
    猜你喜欢
    • 2014-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 2013-06-02
    • 1970-01-01
    相关资源
    最近更新 更多