从Django中的ManytoMany关系中排除一行

时间:2018-06-11 16:40:15

标签: python django django-models django-queryset django-orm

这是我的用户对象,

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True, max_length=255)
    mobile = PhoneNumberField(null=True)
    username = models.CharField(null=False, unique=True, max_length=255)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)

这是我的测验对象,

class Quiz(Base):
    category = models.ForeignKey(Category, related_name='quizzes', on_delete=models.CASCADE)
    players = models.ManyToManyField(User)

这是我用来查找用户尚未播放的特定类别的测验的过滤器,

quiz = Quiz.objects.filter(category=category).exclude(players=user).order_by('created')[:1]

但是排除是一个列表,因此不起作用。如何正确构建此查询以排除当前用户?

1 个答案:

答案 0 :(得分:1)

这个答案旨在回答以下问题(因为它相当复杂,我想确保它完全匹配):

  

包含Quiz zes的查询集,我们在Quiz列表中排除了users zes hat 一个参与者”。所以那些测验是不是查询集的一部分。

我每次都会计算重叠次数,然后排除重叠次数等于零的Quiz zes。类似的东西:

Quiz.objects.filter(
    Q(players__in=users) | Q(players__isnull=True)
).annotate(
    overlap_size=Count('players')
).exclude(overlap_size=1)

因此,我们始终计算“重叠”:users列表中 的用户数以及参与者列表中的用户数 。然后我们排除Quiz zes,其中重叠只有一个,因此确定了users列表中确切存在一个参与者的位置。

如果你想要重叠只有一个的测验,你只需要用.exclude(..)替换.filter(..)(在最后)。