如何通过最新的相关模型过滤Django查询集?

时间:2019-05-16 20:43:00

标签: django django-models

想象一下,在一个人为的示例中,我有以下两个模型:

class User(models.Model):
    name = models.CharField()

class Login(models.Model):
    user = models.ForeignKey(User, related_name='logins')
    success = models.BooleanField()
    datetime = models.DateTimeField()

    class Meta:
        get_latest_by = 'datetime'

如何获取用户查询集,其中仅包含上次登录失败的用户。

我知道以下内容不起作用,但它说明了我想要得到的内容:

User.objects.filter(login__latest__success=False)

我猜我可以用Q对象和/或Case when,和/或其他形式的注释和过滤来做到这一点,但是我无法解决它。

3 个答案:

答案 0 :(得分:2)

我们可以在此处使用Subquery

from django.db.models import OuterRef, Subquery

latest_login = Subquery(Login.objects.filter(
    user=OuterRef('pk')
).order_by('-datetime').values('success')[:1])

User.objects.annotate(
    latest_login=latest_login
).filter(latest_login=False)

这将生成如下查询:

SELECT auth_user.*, (
    SELECT U0.success
    FROM login U0
    WHERE U0.user_id = auth_user.id
    ORDER BY U0.datetime DESC
    LIMIT 1
  ) AS latest_login
FROM auth_user
WHERE (
    SELECT U0.success
    FROM login U0
    WHERE U0.user_id = auth_user.id
    ORDER BY U0.datetime
    DESC LIMIT 1
  ) = False

因此,Subquery的结果是最新success对象的Login,如果是False,则将相关的User添加到QuerySet

答案 1 :(得分:0)

对于支票bool使用success=False,对于最新使用latest() 您的过滤器看起来如下:

User.objects.filter(success=False).latest()

答案 2 :(得分:0)

您可以先注释最大日期,然后使用F expressions根据成功和最大日期进行过滤:

User.objects.annotate(max_date=Max('logins__datetime'))\
    .filter(logins__datetime=F('max_date'), logins__success=False)