带有反向引用的Django查询集过滤器

piok6c0g  于 2022-12-14  发布在  Go
关注(0)|答案(2)|浏览(98)

我是一个C++开发者,也是python的新手,只是在学习django教程。
我想知道如何通过反向引用的信息过滤查询集。
下面是我的模型。

# models.py

import datetime
from django.db import models
from django.utils import timezone

class Question(models.Model):
  pub_date = models.DateTimeField('date published')

class Choice(models.Model): 
  question = models.ForeignKey(Question, on_delete=models.CASCADE)

现在,我想获取Question的查询集,其中pub_date是从现在起过去的,并且被任何Choice引用。
下面是我的尝试。

# First method
question_queryset = Question.objects.filter(pub_date__lte=timezone.now())
for q in question_queryset.iterator():
  if Choice.objects.filter(question=q.pk).count() == 0: 
    print(q)
    # It works. Only @Question which is not referenced 
    # by any @Choice is printed. 
    # But how can I exclude @q in @question_queryset?
    
# Second method
question_queryset = Question.objects.filter(pub_date__lte=timezone.now()
  & Choice.objects.filter(question=pk).count()>0) # Not works.
# NameError: name 'pk' is not defined
# How can I use @pk as rvalue in @Question.objects.filter context?

是因为我不熟悉Python语法吗?还是因为处理数据的方法本身就有问题?你有什么好主意可以在不改变模型的情况下解决我的问题吗?

编辑:我刚刚找到了第一种方法。

# First method
question_queryset = Question.objects.filter(pub_date__lte=timezone.now())
for q in question_queryset.iterator():
  if Choice.objects.filter(question=q.pk).count() == 0: 
    question_queryset = question_queryset.exclude(pk=q.pk)

一个新的关切出现了:如果@Question的行数是n,@Choice的行数是m,那么上面的方法要花O(n * m)次,对吗?有什么方法可以提高性能吗?会不会是我处理数据的方式有问题?或者是数据的结构有问题?

k97glaaz

k97glaaz1#

下面是有关如何反向跟踪关系的文档。以下查询将生成相同的结果:

queryset = (Question.objects
                    .filter(pub_date__lte=timezone.now())
                    .annotate(num_choices=Count('choice')) 
                    .filter(num_choices__gt=0))

依赖Django ORM可能比编写自己的过滤器更好,我相信在最好的场景中时间复杂度是一样的。
与设计有关,这种关系会导致数据库中的重复,不同的问题有时会有相同的答案。我可能会选择多对多的关系。

vsnjm48y

vsnjm48y2#

这不是查询集的工作方式,迭代查询集就是迭代数据库返回的查询集中的每个数据,你不需要使用iterate()

question_queryset = Question.objects.filter(pub_date=timezone.now())
for q in question_queryset:
    if Choice.objects.filter(question=q.pk).count() == 0: 
        print(q)

我没测试过。但应该能用。

相关问题