2015-02-23 26 views
0

我正在建模一个系统,该系统使用一个配方中的少量输入来创建输出。输入具有输出属性的子集,但复杂的是输出也可以用作输入。配方需要不同数量的不同输入。理想情况下,我想这样做:如何最好地构建django模型以适应场景?

class CommonAttrs(models.Model): 
    name = model.CharField() 
    value = model.FloatField() 
    cost = model.FloatField() 

    class Meta: 
     abstract = True 

class Input(CommonAttrs): 
    pass 

class Output(CommonAttrs): 
    price = model.FloatField() 
    demand = model.FloatField() 
    ... 

class Recipe(models.Model): 
    output = model.ForeignKey(Output) 
    input_1 = model.OneToMany([Input, Output]) # I can dream 
    quantity_1 = model.FloatField() 
    input_2 = model.OneToMany([Input, Output]) 
    quantity_2 = model.FloatField() 
    input_3 = model.OneToMany([Input, Output]) 
    quantity_3 = model.FloatField() 
    input_4 = model.OneToMany([Input, Output]) 
    quantity_4 = model.FloatField() 

然而,代替在Django一个一对多的关系,我做:

class Recipe(models.Model): 
    output = model.ForeignKey(Output) 
    input = model.ManyToManyField(Input, through='Measures') 

class Measures(models.Model): 
    recipe = model.ForeignKey(Recipe) 
    input = model.ForeignKey(Input) 
    quantity = model.FloatField() 

这是所有罚款,但错过的关键细节输出也是配方的输入。我在数据库中创建一个视图,并试图在地方输入来创建一个新的非托管模式:

class InputOrOutput(CommonAttrs): 

    class Meta: 
     managed = False 
     db_table = 'input_union_output_view' # Does what is says on the tin 

然而,这导致与初始化和迁移问题的泥潭。

我最后的手段是创建一个完整的表格而不是视图,但是这感觉就像是从不一致的数据中寻找令人头痛的问题。

有什么更好的选择?

+0

好的。所以输出也可以是输入。首先我想知道的是,如果将它们放在一个表中,可能会用布尔值表示“仅输入”,如果相关的话会更有意义。如果你想用'input_1'做的事情是链接到输入*或*输出,那实际上是可能的,它只需要更多的字段。如果我们能够澄清将这些分为两个表格的必要性,很高兴提供一些代码。通用FK文档在这里:https://docs.djangoproject.com/en/1。7/ref/contrib/contenttypes /#generic-relations – dylrei 2015-02-23 23:10:33

+0

作为第二个问题,您是否真的想在一个配方中设计特定数量的输入/输出,或者是否需要为每个配方设计许多输入/输出?输入/输出是否用于多个配方? – dylrei 2015-02-23 23:12:37

+0

不要紧,你应该从提供的答案开始。它可能需要调整你的确切情况,但这是一个很好的开始。 – dylrei 2015-02-23 23:22:29

回答

3

假设,即每输入和输出不能在同一个表去评论,那通用外键可能是有合到模型的关系最好的选择。从你的配方代码开始:

from django.contrib.contenttypes.fields import GenericForeignKey 
from django.contrib.contenttypes.models import ContentType 

class Recipe(models.Model): 
    output = model.ForeignKey(Output) 
    input_1_content_type = models.ForeignKey(ContentType) 
    input_1_object_id = models.PositiveIntegerField() 
    input_1_content_object = GenericForeignKey('input_1_content_type', 'input_1_object_id') 
    quantity_1 = model.FloatField() 

这将为您提供一个通用的FK for input_1。如果您必须手动执行每个输入,那么这是很多代码,但也许没关系。

如果有一种简单的方法可以实现通用M2M开箱即可,但我不相信。相反,也许一个中级班会让你走到那里:

class Recipe(models.Model): 
    output = model.ForeignKey(Output) 
    @property 
    def inputs(self): 
     return self.recipeinput_set 


class RecipeInput(models.Model): 
    recipe = models.ForeignKey(Recipe) 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = GenericForeignKey('content_type', 'object_id') 
    quantity = model.FloatField() 
+0

谢谢!泛型关系似乎正是我正在寻找的。而且由于需要手动定义反向关系,所以中间类是更为理想的选择。 – 2015-02-24 00:29:05

+0

经过测试,效果很好。 – 2015-02-24 03:24:36

1

不知道InputOutput是什么,我会承担它的食物。这很方便。

配方使用食物来生产不同类型的食物。

class Recipe(models.Model): 
    output = model.ForeignKey(Food, related_name="produced_by") 
    input = model.ManyToManyField(Food, through='Measures') 

例如(该代码可以或可以不工作,但示出的点):

cheese = Food("Cheese") 
bread = Food("Bread") 
toasty = Food("Toasted Cheese Sandwich") 

toasty.produced_by = Recipe(input=[cheese,bread]) 

A输入度量然后只是引用Food项。

每个Food然后有一个购买和销售价格 - 假如有什么从买奶酪,然后卖它阻止我。

class Food(models.Model): 
    name = model.CharField() 
    value = model.FloatField() 
    purchase_price = model.FloatField() 
    sale_price = model.FloatField() 
    demand = model.FloatField() 
+0

不幸的是,输入和输出在实质上是不同的,在不同的地方使用,我希望在语义上对待它们。另外,在这种情况下,这些输入是不能产生这些输出的不同过程的结果。 – 2015-02-23 23:30:54