Django ORM 查询多个关联字段的方法

6

如何将这个 mysql 查询转换为 Django ORM?

SELECT search_products.model, search_products.year, search_products.size, search_avg_price.estimated_price
FROM search_products
left JOIN search_avg_price
ON search_products.model=search_avg_price.model and search_products.size=search_avg_price.size and search_products.year=search_avg_price.year

我已经尝试过

latest_products = Products.objects.all().prefetch_related("avg_price")

但这被 Django 翻译为
SELECT `search_products`.`id`, `search_products`.`size`, `search_products`.`year`, , `search_products`.`model`, `search_products`.`avg_price_id`
FROM `search_products`

并且

latest_products = Products.objects.all().select_related("avg_price")

这是由Django翻译的:

SELECT `search_products`.`id`, `search_products`.`size`, `search_products`.`year`, , `search_products`.`model`, `search_products`.`avg_price_id`, `search_avg_price`.`id`, `search_avg_price`.`model`, `search_avg_price`.`size`, `search_avg_price`.`year`, `search_avg_price`.`estimated_price` 
FROM `search_products` 
INNER JOIN `search_avg_price` ON ( `search_products`.`avg_price_id` = `search_avg_price`.`id` )

如果我在数据库中运行上述SQL语句,我会得到正确的结果...
编辑:模型和视图
class Avg_price(models.Model):
 model = models.CharField(max_length=50, blank=True)
 size= models.IntegerField(blank=True, null=True)
 year= models.IntegerField(blank=True, null=True)
 estimated_price= models.IntegerField(blank=True, null=True)

class Products(models.Model):
 product_id =models.IntegerField(blank=True, null=True)
 link_id = models.CharField(max_length=200, blank=True)
 location = models.CharField(max_length=200, blank=True)
 model = models.CharField(max_length=50, blank=True)
 size= models.IntegerField(blank=True, null=True)
 price= models.IntegerField(blank=True, null=True)
 year= models.IntegerField(blank=True, null=True)
 type=models.ForeignKey(Type)
 avg_price = models.ForeignKey(Avg_price)

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

模板

{% if latest_products %}
  {% for product in latest_products %}
  <ul>
    <li id="col_one">
      <h5>{{product.avg_price.estimated_price}}</h5>
      <h5>{{product.model}}</h5>

你不需要使用select_related或者prefetch_related,而是使用filter来与另一个模型绑定,假设存在外键或多对多关系。你可以发布你的模型代码吗? - Tom
2个回答

3
您可以将表格列表传递给extra()方法,并将您的SQL查询的ON条件放入where部分中的extra()中。
Product.objects.extra(
    tables=['search_avg_price'],
    where=[
        '"search_products"."model"="search_avg_price"."model"',
        '"search_products"."size"="search_avg_price"."size"',
        '"search_products"."year"="search_avg_price"."year"'
   ]
)

了解更多关于extra:

https://docs.djangoproject.com/en/1.6/ref/models/querysets/#extra

有没有一种方式可以访问通过.extra()连接的search_avg_price表的值?官方文档非常简洁。 :( - Ihor Pomaranskyy

1
尝试像这样查询:
qs = Product.objects.filter(
    avg_price__model__isnull=True).filter(
    avg_price__size__isnull=True).filter(
    avg_price__year__isnull=True).values_list(
    'model', 'year', 'size', 'avg_price__estimated_price')

测试:

print(qs.query)

解释:

从您的产品模型中,每次在 avg_price 上访问 ForeignKey 和该模型中的相关字段时,您希望在基于 LEFT JOIN 返回查询时每次将其设置为 NULL。以下是跨关系查找的文档:

https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships

然后,values_list 允许您指定要返回的值。这是有关 values_list 的文档:

https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.values_list


我尝试过并出现了错误:"FieldError: Cannot resolve keyword 'avg_price.estimated_price' into field"。似乎django无法看到其他表...此外,我需要显示表格产品中的所有结果,并在存在时添加来自表格avg_price的结果(年份、型号和尺寸匹配)...感谢您的帮助。 - user2950162
avg_price__estimated_price 代替 avg_price.estimated_price 怎么样? - Aaron Lelevier
1
生成的查询与我想要构建的不同...从 search_products 内连接到 search_avg_price,条件为 search_products.avg_price_id = search_avg_price.id,选择 search_productsmodelsearch_products.yearsearch_products.sizesearch_avg_price.estimated_price。其中 (search_avg_price.model 为空且 search_avg_price.size 为空且 search_avg_price.year 为空)。 - user2950162

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接