Django:如何根据第二个 table 的属性过滤内部连接?

Django: How to filter on inner join based on properties of second table?

我的问题很简单:在 Django 应用程序中,我有一个 table Users 和一个 table StatusUpdates。在 StatusUpdates table 中,我有一列 user,它是指向 Users 的外键。我如何进行搜索,表达如下内容:

users.filter(latest_status_update.text__contains='Hello')

编辑:

请原谅我不够清晰。我想进行的查询类似于 "Give me all the users whose latest status update contains the text 'hello'"。在 Django 代码中,我会执行以下操作(这确实是低效且丑陋的):

hello_users = []
for user in User.objects.all():
  latest_status_update = StatusUpdate.objects.filter(user=user).order_by('-creation_date')[0]
  if latest_status_update.text.contains('Hello'):
    hello_users.append(user)

return hello_users

编辑 2:

我已经找到了解决方案,但既然有人问我,这里是我模型的重要部分:

class User(models.Model):
  ...

class StatusUpdate(models.Model):
  user = models.ForeignKey(User)
  text = models.CharField(max_length=140)
  creation_date = models.DateTimeField(auto_now_add=True, editable=False)
  ....

不确定我是否理解,你是不是想做类似

的事情
(StatusUpdates
    .objects
    .select_related("user")
    .filter(text__contains = "hello")
    .order_by("-updated")
    .first())

这将 return 上次修改的 StatusUpdate(如果您有一个名为 updated 的字段存储上次修改的时间),它在文本字段中包含 "Hello"。如果 StatusUpdates 的 none 包含该字符串,它将 return None.

那么你可以这样做:

latest = (StatusUpdates
    .objects
    .select_related("user")
    .filter(text__contains = "hello")
    .order_by("-updated")
    .first())
#then if you needed the user too
if latest is not None:
    user = latest.user #which does not call the DB again since you selected related` 

如果这不是您需要的,请提供更多详细信息(型号)并阐明您的需求

latest_status_updates = filter(lambda x: x.text.contains('hello'),
    [
        user.statusupdates_set.order_by('-creation_date').first() 
        for user in User.objects.all()
    ]
)
users = list(set([status_update.user for status_update in latest_status_updates]))

编辑: 现在我首先将每个用户的所有最新状态更新放入一个列表中,然后通过在 StatusUpdate class 中找到的文本字段进行过滤。在第二行中,我从过滤的状态更新中提取用户,然后生成一个唯一的用户列表。

希望对您有所帮助!

好的,我想我明白了:

from django.db.models import Max, F

User.objects\
  .annotate(latest_status_update_id=Max('statusupdate__id'))\
  .filter(
    statusupdate__id=F('latest_status_update_id'), 
    statusupdate__text__icontains='hello'
  )

有关详细信息,请参阅 this section of the Django documentation

请注意: 我最终稍微改变了我的策略并采用了最高 ID 表示最新更新的策略。之所以如此,是因为我意识到用户可以同时 post 两次更新,这会破坏我的查询。