2

https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships上,Django 团队描述了比萨和浇头上下文中的多对多关系。我以他们为例,试图找到解决我在建模自己的数据时遇到的概念问题的方法。

为了准确解释这篇 Stack Overflow 帖子我要完成的工作,请考虑以下(假设的)语法:

TOPPING = {'a'..'z' | 'A'..'Z'};
FLOAT = {'0'..'9'}, ['.', {'0'..'9'}]; (* Non-negative numbers only *)

QUERY = "Hey Django, find me all of the pizzas in the database such that:",
      { "(", (TOPPING), (">=" | "<=" | "=="), FLOAT, ") &&" },
      "(", (TOPPING, (">=" | "<=" | "=="), FLOAT, ")";

这是我试图观察的从发出类似于 QUERY 的内容返回的 QuerySet。正如其内容所暗示的,我希望 Django 向我返回一个 QuerySet,其中包含满足我筛选标准的所有 Pizza 对象。我对 models.py 的外观或实际查询的外观没有信心。我只有足够的经验来解释上面的伪查询和我希望返回的结果。

提前感谢您,我期待着阅读您的建议。

额外信息

请注意,在我的特定情况下,加载初始数据后永远不会写入数据库。阅读总是非常频繁。

我愿意使用原始 SQL,但我更喜欢使用 Django QuerySet API


在解决方案中尝试 1:

我在模型中添加了一个 ToppingAmount(models.Model) 类。我给了它一个金额的浮点数,还有两个外键将披萨和浇头与金额相关联。

from django.db import models
class Topping(models.Model):
  name = models.CharField(max_length=128)

  # On Python 3: def __str__(self):
  def __unicode__(self):
    return self.name

class Pizza(models.Model):
  name = models.CharField(max_length=128)
  toppings = models.ManyToManyField(Topping, through='ToppingAmount')

  # On Python 3: def __str__(self):
  def __unicode__(self):
    return self.name

class ToppingAmount(models.Model):
  topping = models.ForeignKey(Topping)
  pizza = models.ForeignKey(Pizza)
  amount = models.FloatField()
  units = models.CharField(max_length=4) # e.g. 'g' | 'kg' | 'lb' | 'oz' ...

上面的模型将允许一个人(例如)执行 aToppingAmount.objects.filter(topping__name='foo').filter(amount__gt=bar)并找到所有的ToppingAmount对象,这样它的比萨饼上至少有 bar 克的 foo 。

不幸的是,它也允许反常的ToppingAmount.objects.filter(pizza__name='pippo').filter(amount__gt=bar)人找到所有的ToppingAmount对象,这样它的顶部至少有 bar 克的“pippo”。

这是我能用这个模型和简单的过滤器得到的。我们无法根据其他配料(或比萨饼;))和金额过滤生成的 QuerySet,因为此 QuerySet 仅包含ToppingAmount对象。此 QuerySet 中的每个 ToppingAmount 对象将具有相同的浇头或相同的比萨饼。它们的所有数量(无论是解释为描述浇头还是比萨饼)也将符合filter(amount...).

此外,我观察到在这里使用多对多关系没有明显的好处。从 Pizza 类中删除浇头,同时保持其他所有内容相同会导致数据库具有相同的 json 转储和来自可能查询的相同实用程序。


尝试2:

创建一个 Pizza 表,其中包含所有 146 种可能的配料的列。

from django.db import models
class Topping(models.Model):
  name= modles.CharField(max_length=128)
  units = models.CharField(max_length=4) # e.g. 'g' | 'kg' | 'lb' | 'oz' ...

class Pizza(models.Model):
    name = models.CharField(max_length=128)
    topping1_amount = models.FloatField()
    .
    .
    .
    topping146_amount = models.FloatField()

    # On Python 3: def __str__(self):
    def __unicode__(self):
        return self.name

我很谨慎地相信这个解决方案,因为它创建了一个我认为不必要或不可取的大而稀疏的表(赞赏评论)。另一方面,为这个模型编写查询非常简单:Pizza.objects.filter(topping1_amount__gt=20).filter(topping2_amount__lt=15)...

4

0 回答 0