Django模型关系最佳解决方案

时间:2017-05-25 12:13:12

标签: python django django-models django-rest-framework

我有以下型号:

BasketFruit

Basket可以包含多个Fruit个对象,而Fruit属于单个Basket。每个Fruit都可以手动排序,以便在列出时,它们会显示保存顺序。到现在为止还挺好。

class Basket (models.Model):
    # A fruit basket
    name = models.CharField(max_length=100)
    is_virtual = models.BooleanField(default=False)
    # This is just a badly constructed example of how a list
    # of basket primary keys are saved when creating the virtual basket
    # This is only for demonstration purposes to solve the overall modelling issue
    virtual_baskets = models.TextField(null=True)

class Fruit (models.Model):
    # The basket this fruit belongs to
    basket = models.ForeignKey("Basket", related_name="fruits", on_delete=models.CASCADE)

    # Manually sorted order
    order = models.PositiveIntegerField(default=0)

然而,Basket上有一个名为is_virtual的标志,它允许用户从现有的真实篮子中创建虚拟组合篮子,在这种篮子中你最终会略微违反规则:虚拟篮子实际上可以将两个现有的BasketsFruit两个篮子组合在一起。我需要能够允许用户手动对这些篮子中的Fruit进行排序和重新排序,而不会覆盖原始篮子中的排序。

举个例子:

Basket A按顺序包含:Apple,Banana

Basket B按顺序包含:Orange,Grapes

我现在想创建一个虚拟Basket C,它会像A和B一样展示水果:

Apple,Grapes,Banana,Orange

要注意的一个注意事项:虚拟篮子只是将各种其他篮子的结果组合在一起。对于用户来说,它仍然是一个有效的篮子,他们应该能够重新订购水果。

如何建立这种排序关系?我正在考虑添加一个新模型:

class FruitAppearance (models.Model):
    # The basket this appearance is tied to
    basket = models.ForeignKey("Basket", related_name="manually_sorted_fruits", on_delete=models.CASCADE)

    # The fruit it represents
    fruit = models.ForeignKey("Fruit", on_delete=models.CASCADE)

    # Order
    order = models.PositiveIntegerField(default=0)

我认为是对的吗?有没有更好的办法?我应该在现有的FruitBasket模型中使用ManyToManyField吗?

2 个答案:

答案 0 :(得分:0)

我建议如下。 将您的模型分开篮子和虚拟篮子,结果删除虚拟场。

因此每个Fruit可以属于一个Basket(ForeignKey),但同时属于多个Virtual Baskets(ManyToManyField)。在manytomany字段中使用参数throught并包含另一个模型,该模型将仅存储特定虚拟购物篮的水果顺序。

class Fruit (models.Model):
    # The basket this fruit belongs to
    basket = models.ForeignKey("Basket", related_name="fruits", on_delete=models.CASCADE)
    virtual_basket = models.ManyToManyField(Fruit, through='FruitOrdering')

    # Manually sorted order
    order = models.PositiveIntegerField(default=0)

答案 1 :(得分:0)

class Basket(models.Model):
    name = models.CharField(max_length=100)
    fruits = models.ManyToMany("Fruit", through="FruitBasket")
    ...

class Fruit(models.Model):
    ...

class FruitBasket(models.Model:
    basket = models.ForeignKey("Basket", on_delete=models.CASCADE)
    fruit = models.ForeignKey("Fruit", on_delete=models.CASCADE)
    order = models.PositiveIntegerField(default=0)
    ...

通过这种方式,您可以获得一些数据冗余,但可以为每个购物篮中的水果设置不同的订单号。