如何最好地构建 Django 模型以适应场景?

How best to architect django models to fit a scenario?

我正在对一个系统建模,该系统涉及一个过程,该过程使用配方中的少量输入来创建输出。输入具有输出属性的子集,但复杂的是输出也可以用作输入。食谱需要不同数量的不同输入。理想情况下,我想这样做:

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 中的 OneToMany 关系,我做了:

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

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

我的最后一招是创建一个完整的 table 而不是视图,但这感觉像是在为不一致的数据找麻烦。

有哪些更好的选择?

在不知道 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])  

输入度量然后仅引用 Food 项。

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

然后每个 Food 都有购买和销售价格 - 假设没有什么能阻止我购买和出售奶酪。

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

假设,根据输入和输出不能在同一个 table 中的评论,那么通用外键​​可能是建立绑定到任一模型的关系的最佳选择。从您的食谱代码开始:

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

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

如果有一种开箱即用的通用 M2M 的简单方法就好了,但我不相信有。相反,也许中级 class 可以帮助您完成大部分工作:

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