Django 结合 2 个查询集
Posted
技术标签:
【中文标题】Django 结合 2 个查询集【英文标题】:Django combine 2 QuerySets 【发布时间】:2020-04-27 09:04:36 【问题描述】:我有 2 个针对同一数据库中不同表的查询集。
我想要实现的是通过created_at
过滤results
,然后通过hit_count
。
我将 django-hitcount 用于hit_count
这是模型
class Post(models.Model):
STATUS_CHOICES = (
(1, 'Technology'),
(2, 'Security'),
(3, 'android|ios'),
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, unique=True, editable=False)
title = models.CharField(max_length=250)
body = models.TextField()
main_image = models.ImageField(null=False, upload_to=save_image)
second_image = models.ImageField(blank=True, default="")
third_image = models.ImageField(blank=True, default="")
fourth_image = models.ImageField(blank=True, default="")
fifth_image = models.ImageField(blank=True, default="")
slug = models.SlugField(blank=True, default="", editable=True)
created_at = models.DateField(default=date.today)
category = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, default=1)
custom = managers.PostManager()
这是Manager
class PostManager(models.Manager):
def get_queryset(self):
return super(PostManager, self).get_queryset()
def get_tech(self):
return self.get_queryset().filter(category=1)
def get_security(self):
return self.get_queryset().filter(category=2)
def get_mobile(self):
return self.get_queryset().filter(category=3)
def get_category_count(self):
return self.get_tech().count(), self.get_security().count(), self.get_mobile().count()
def get_top_stories_of_month(self):
s_date = datetime.strftime(datetime.now() - timedelta(days=25), '%Y-%m-%d')
e_date = datetime.strftime(datetime.now() - timedelta(days=32), '%Y-%m-%d')
qs1 = self.get_queryset().filter(Q(created_at__lte=s_date) | Q(created_at__gte=e_date))
qs2 = HitCount.objects.order_by('hits')
如您所见,我已将结果存储到 qs1 和 qs2,但不知道如何组合它们。
我也曾在 shell 中玩过,试图通过它们共有的 object_pk 过滤掉query_set
中的对象。结果很奇怪,当比较 pk 时,由于某种原因它返回 False
。
代码来自 Shell
>>> p = Post.custom.get_top_stories_of_month()
>>> h = HitCount.objects.order_by('hits')
>>> p
<QuerySet [<Post: dddddddddddddddddd>, <Post: kljlkjlkj>, <Post: asdasdad>, <Post: aasdfasdf>, <Post: zvzxv>]>
>>> h
<QuerySet [<HitCount: asdasdad>, <HitCount: zvzxv>, <HitCount: aasdfasdf>, <HitCount: kljlkjlkj>, <HitCount: dddddddddddddddddd>]>
>>> for i in h:
... print(i.object_pk)
... for j in p:
... print(j.pk)
... print(i.object_pk == j.pk)
...
868ca0d9-f324-4845-b34b-38a1203eacb3
72b2104f-2cb6-49b3-80fd-fd0e80fab5b1
False
889d895b-f73c-48ca-9a96-064cbe6292c1
False
868ca0d9-f324-4845-b34b-38a1203eacb3
False
762f1c29-6ba5-4aaf-99a3-833c8c60d126
False
4b6427b1-4dab-4705-b5de-d39ccccec119
False
4b6427b1-4dab-4705-b5de-d39ccccec119
72b2104f-2cb6-49b3-80fd-fd0e80fab5b1
False
889d895b-f73c-48ca-9a96-064cbe6292c1
False
868ca0d9-f324-4845-b34b-38a1203eacb3
False
762f1c29-6ba5-4aaf-99a3-833c8c60d126
False
4b6427b1-4dab-4705-b5de-d39ccccec119
False
762f1c29-6ba5-4aaf-99a3-833c8c60d126
72b2104f-2cb6-49b3-80fd-fd0e80fab5b1
False
889d895b-f73c-48ca-9a96-064cbe6292c1
False
868ca0d9-f324-4845-b34b-38a1203eacb3
False
762f1c29-6ba5-4aaf-99a3-833c8c60d126
False
4b6427b1-4dab-4705-b5de-d39ccccec119
False
889d895b-f73c-48ca-9a96-064cbe6292c1
72b2104f-2cb6-49b3-80fd-fd0e80fab5b1
False
889d895b-f73c-48ca-9a96-064cbe6292c1
False
868ca0d9-f324-4845-b34b-38a1203eacb3
False
762f1c29-6ba5-4aaf-99a3-833c8c60d126
False
4b6427b1-4dab-4705-b5de-d39ccccec119
False
72b2104f-2cb6-49b3-80fd-fd0e80fab5b1
72b2104f-2cb6-49b3-80fd-fd0e80fab5b1
False
889d895b-f73c-48ca-9a96-064cbe6292c1
False
868ca0d9-f324-4845-b34b-38a1203eacb3
False
762f1c29-6ba5-4aaf-99a3-833c8c60d126
False
4b6427b1-4dab-4705-b5de-d39ccccec119
False
【问题讨论】:
【参考方案1】:django-hitcount 的文档描述了 here 如何将字段添加到您的模型之一 (Post
),该字段将与 HitCount
模型相关。
按照文档中的示例将hit_count
属性添加到相关的Post
模型后,您可以在查询中按点击次数和发布日期排序和/或过滤。您的查询看起来像这样:
top_posts = Post.objects.order_by("hit_count__hits").filter(Q(created_at__lte=s_date) | Q(created_at__gte=e_date))
【讨论】:
【参考方案2】:遗憾的是,当order_by('hit_count.hits')
时,我无法让查询变得优雅,因为它应该出现一些关系错误
决定这样做:
s_date = datetime.strftime(datetime.now() - timedelta(days=25), '%Y-%m-%d')
e_date = datetime.strftime(datetime.now() - timedelta(days=32), '%Y-%m-%d')
qs1 = self.get_queryset().filter(Q(created_at__lte=s_date) |
Q(created_at__gte=e_date))
mlist = sorted(list(qs1), key=lambda obj: obj.hit_count.hits, reverse=True)
return mlist[:2]
这将返回 2 个观看次数最多的帖子。
【讨论】:
以上是关于Django 结合 2 个查询集的主要内容,如果未能解决你的问题,请参考以下文章
Graphene-Django:在模式中结合查询对象(只接受第一个参数)