2012-03-22 41 views
1

我有一个沙盒,其中包含大量由一个或多个属性组成的项目。每个属性都属于一个特定的属性类型(如颜色,形状等) 我对如何渲染带有属性的属性以及它们的属性类型的表现感到迷茫。通过输入形式对很多选项进行分组

模型

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}) 

调用形式我调用此工厂方法为: 形式= make_sandbox_form()

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

(我希望我能给予好评所有,但作为一个StackOverflow的菜鸟我缺乏声望如此。)

+1

你是否看了['regroup'(https://docs.djangoproject.com/en/dev/ref/templates/builtins/? from = olddocs#regroup)模板标记(允许您按属性分组) – 2012-03-22 15:22:17

+0

是的,我找不到使用表单实现它的方法,只能使用查询集。我在想,这个问题可以通过制作一个新的表单渲染方法来解决......问题是如何...... – droidballoon 2012-03-22 15:29:35

回答

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) 

这也保证你只有每选择,因为在ForeignKey的默认django.Forms你到ChioceField(IIRC)。

至于从而覆盖并使其成为一个单选按钮,只需查看文档在这里:

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

+0

是的,你的锐利眼睛注意到我错过了Item到Sandbox的引用。更新我的问题。谢谢!关键是我无法为每种类型创建单独的模型,因为它们将通过管理界面添加到用户中。 AttributeTypes的数量可能超出我最初的想法。 – droidballoon 2012-03-22 15:24:25

+1

@droidballoon你仍然可以将它们分开并将数据输入推送给用户。如果颜色不存在,只需给他们一个选项来创建一个新的颜色/形状。 – 2012-03-22 15:47:51

+0

确实,我的意思是,如果用户想要创建一个新的AttributeType,比如说'声音',那么开发人员必须为此AttributeType创建一个新模型以适应这种变化。或者我错过了什么? – droidballoon 2012-03-22 16:04:34