django - 在同一模型上应用 union() 无法识别使用 GenericRelation 的排序
问题描述
我有一个这样的文章模型
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from hitcount.models import HitCountMixin, HitCount
class Article(models.Model):
title = models.CharField(max_length=250)
hit_count_generic = GenericRelation(
HitCount, object_id_field='object_pk',
related_query_name='hit_count_generic_relation')
当我这样做时Article.objects.order_by('hit_count_generic__hits')
,我会得到结果。但是当我这样做时
articles_by_id = Article.objects.filter(id__in=ids).annotate(qs_order=models.Value(0, models.IntegerField()))
articles_by_name = Article.objects.filter(title__icontains='sports').annotate(qs_order=models.Value(1, models.IntegerField()))
articles = articles_by_id.union(articles_by_name).order_by('qs_order', 'hit_count_generic__hits')
出错
ORDER BY 术语与结果集中的任何列都不匹配
我怎样才能实现这样的联合?我不得不使用联合而不是 AND 和 OR,因为我需要保持秩序。IE; article_by_id 应该排在第一位,articles_by_name 应该排在第二位。
使用 Django hitcount 作为 hitcount https://github.com/thornomad/django-hitcount。Hitcount 模型如下所示。
class HitCount(models.Model):
"""
Model that stores the hit totals for any content object.
"""
hits = models.PositiveIntegerField(default=0)
modified = models.DateTimeField(auto_now=True)
content_type = models.ForeignKey(
ContentType, related_name="content_type_set_for_%(class)s", on_delete=models.CASCADE)
object_pk = models.TextField('object ID')
content_object = GenericForeignKey('content_type', 'object_pk')
objects = HitCountManager()
正如@Angela 所建议的那样,尝试了相关的预取。
articles_by_id = Article.objects.prefetch_related('hit_count_generic').filter(id__in=[1, 2, 3]).annotate(qs_order=models.Value(0, models.IntegerField()))
articles_by_name = Article.objects.prefetch_related('hit_count_generic').filter(title__icontains='date').annotate(qs_order=models.Value(1, models.IntegerField()))
选中时 prefetch_related 的查询根本没有选择命中计数。
SELECT "articles_article"."id", "articles_article"."created", "articles_article"."last_changed_date", "articles_article"."title", "articles_article"."title_en", "articles_article"."slug", "articles_article"."status", "articles_article"."number_of_comments", "articles_article"."number_of_likes", "articles_article"."publish_date", "articles_article"."short_description", "articles_article"."description", "articles_article"."cover_image", "articles_article"."page_title", "articles_article"."category_id", "articles_article"."author_id", "articles_article"."creator_id", "articles_article"."article_type", 0 AS "qs_order" FROM "articles_article" WHERE "articles_article"."id" IN (1, 2, 3)
解决方案
ORDER BY 术语与结果集中的任何列都不匹配
您收到此错误,因为这正是正在发生的事情。您的文章最终结果集不包含来自hitcount 表的 hits 列,因此结果集无法使用此列进行排序。
在深入研究答案之前,让我们看看您的 django 查询集在幕后发生了什么。
检索一组特定的文章并包括一个额外的排序字段 qs_order 设置为 0。
articles_by_id = Article.objects.filter(id__in=ids).annotate(qs_order=models.Value(0, models.IntegerField()))
上面的 SQL 查询
Select id, title,....., 0 as qs_order from article where article.id in (Select ....) # whatever you did to get your ids or just a flat list
检索另一组文章并包括一个额外的排序字段 qs_order 设置为 1
articles_by_name = Article.objects.filter(title__icontains='sports').annotate(qs_order=models.Value(1, models.IntegerField()))
上面的 SQL 查询
Select id, title, ...1 as qs_order from article where title ilike '%sports%'
原始查询集和 order_by hit_count_generic__hits
Article.objects.order_by('hit_count_generic__hits')
这实际上将执行内部连接并获取 hitcount 表以按 hits 列排序。
询问
Select id, title,... from article inner join hitcount on ... order by hits ASC
联盟
因此,当您进行联合时,上述 2 个查询的结果集将被组合,然后使用您的qs_order进行排序,然后点击...失败的地方。
解决方案
使用 prefetch_related 在初始查询集过滤中获取您的 hitcount 表,因此您可以使用联合中的 hits 列进行排序。
articles_by_id = Article.objects.prefetch_related('hit_count_generic').filter(id__in=ids).annotate(qs_order=models.Value(0, models.IntegerField()))
articles_by_name = Article.objects.prefetch_related('hit_count_generic').filter(title__icontains='sports').annotate(qs_order=models.Value(1, models.IntegerField()))
现在,当您在两个 SELECT 查询中都有所需的表及其列时,您的联合应该按照您定义的方式工作。
articles = articles_by_id.union(articles_by_name).order_by('qs_order', 'hit_count_generic__hits')
推荐阅读
- c# - 将旧版 ASP.NET WebForms 项目改进为现代标准
- node.js - axios DELETE 方法给出 404 Not Found 错误
- javascript - 使用 lodash 使用一个对象减少另一个对象
- java - 云翻译 API 价格
- excel-formula - 显示特定文本的多个条件
- isabelle - 在这个例子中证明 Isabelle/HOL 的存在
- java - java - 如何使用java中的lamda表达式查找丢失的最小正整数
- powerbi - Power bi:计算累计并乘以每个月的值
- python - Django Rest Framework 展平嵌套的自引用对象
- java - Java Spring Boot在将管理员密码存储到数据库之前对其进行加密?