Django ORM 交叉产品

Posted

技术标签:

【中文标题】Django ORM 交叉产品【英文标题】:Django ORM Cross-Product 【发布时间】:2014-03-29 05:29:26 【问题描述】:

我有以下架构:

class PCs(models.Model):
  model = models.ForeignKey(Products, primary_key=True)
  speed = models.IntegerField(max_length=256, blank = True, null=True)
  ram = models.IntegerField(max_length=256, blank = True, null=True)
  hd = models.IntegerField(max_length=256, blank = True, null=True)
  price = models.IntegerField(max_length=256, blank = True, null=True)


class Printers(models.Model):
  model = models.ForeignKey(Products, primary_key=True)
  color = models.BooleanField()
  type = models.CharField(max_length=256, blank = True, null=True)
  price = models.IntegerField(max_length=256, blank = True, null=True)

我正在尝试运行以下 SQL 查询:

SELECT *
FROM PCs P, Printers T
WHERE p.price + t.price <= 1000

但是我完全不知道如何使用 Django 的 ORM 来做到这一点。除了从 PC 和打印机中获取所有对象并检查所有可能的组合之外,这是唯一的方法吗?

【问题讨论】:

有点吹毛求疵,但按照惯例,型号名称应该是单数。 【参考方案1】:

ORM:

pcs = PCs.objects.filter(price__lte=1000)
printers = Printers.objects.filter(price__lte=1000)

pcsprinter 我们可以找到问题的答案。 而我们的SQL 查询不正确。 或者创建一个related_name,然后从产品中进行一个查询。

【讨论】:

这和我提供的 SQL 查询不一样。这只是获取价格低于 1000 的 pc 和打印机。我想要两张表的叉积,其中 pc 的价格和打印机的价格之和小于 1000 我明白这一点。但这是 Django ORM。 看django连接执行,可以求助。或者使用另一个 ORM。【参考方案2】:

一种可能的解决方案是使用原始 SQL,请参阅文档 here。

不幸的是,django ORM 没有提供一种干净的方法来连接两个没有某种关系的表。不干净不代表做不到!

请注意,我实际上无法说出您的原始 sql 表名称是什么,因此您必须自己填写。如果我不得不猜测它们会是app_name_p_csapp_name_printers。你可以使用./manage.py dbshell去了解。

你可以试试这样的:

pcs = PCs.objects.raw(
    "SELECT "
    "    pc_table.model_id, "
    "    pc_table.speed, "
    "    pc_table.ram, "
    "    pc_table.hd, "
    "    pc_table.price, "
    "    printer_table.model_id as printer_model_id, "
    "    printer_table.color as printer_color, "
    "    printer_table.type as printer_type, "
    "    printer_table.price as printer_price "
    "FROM "
    "    pc_table, printer_table "
    "WHERE "
    "    pc_table.price + printer_table.price <= 1000 "
)

pairs = []
for pc in pcs:
    printer = Printers(
        model_id=pc.printer_model_id,
        color=pc.printer_color,
        type=pc.printer_type,
        price=pc.printer_price,
    )
    pairs.append((pc, printer))

如您所见,打印机字段中的额外值只是附加到您通过 ORM 查询获得的 pc 对象上,之后您只需手动构造打印机对象即可。我认为为查询命名打印机字段是个好主意,这样 ORM 就不会将它们与 pc 字段混淆。

另请注意,根据您打算如何处理此查询的结果,甚至可能根本不需要构造 Printers 对象。

【讨论】:

以上是关于Django ORM 交叉产品的主要内容,如果未能解决你的问题,请参考以下文章

Django循环进入模板,ORM

Django ORM 对 QuerySet 的迭代真的很慢

交叉表左连接,Django ORM

Django ORM 验证数据库中的一行

django orm中的INNER JOIN

在 WooCommerce 中的相关产品上显示同一类别之前的交叉销售