Django ORM-通过过滤的外键关系查询集顺序

时间:2019-06-11 19:52:52

标签: python django postgresql

问题:可以使用Django ORM / queryset函数完成过滤的左联接或子查询的联接(在postgres中非常简单)吗?

型号:

class User(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256)

class DashboardItem(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256)

class DashboardItemUserData(models.Model):
    id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User)
    dashboard_item = models.ForeignKey(DashboardItem)
    is_favorite = BooleanField()

DashboardItemUserData存储有关用户是否“收藏”了仪表板项目的每个用户的信息。我需要能够根据当前发出请求的用户对DashboardItem进行排序。但是,我需要对联接进行过滤,因为排序应尊重当前用户,而不管其他用户是否“收藏”了该项目。

我认为可行的查询(或类似查询):

current_user = request.user
DashboardItem.objects.annotate(is_favorite=DashboardItemUserData.objects.filter(user=current_user).values('is_favorite')).order_by('is_favorite','name')

这就是我要在SQL中执行的操作

postgres query using where on join

postgres query using subquery

2 个答案:

答案 0 :(得分:0)

DashboardItemUserData.objects.filter(user_id=1).\
    annotate(name=dashboard_item__name).\
    order_by('is_favorite', 'name')

如果这是LEFT联接,则子查询很有意义。或是否包含TOP / LIMIT。

答案 1 :(得分:0)

讨厌回答我自己的第一个问题...但是如果其他任何人遇到它,请把它留在这里。我发现有两种方法可以在这里使用:

  1. 如果我们可以保证DashboardItemUserData表中每个用户的数据库记录,我们可以简单地使用“ filter()”创建内部联接。由于用户将拥有所有DashboardItem的记录,因此内部联接不会排除任何记录。
current_user = request.user
DashboardItem.objects.filter(dashboarditemuserdata__user=current_user).order_by('is_favorite', 'name')
  1. 如果我们不能保证DashboardItemUserData中每个用户的记录,我们可以使用Django ORM的FilteredRelation功能。这将创建一个左外部联接,在该联接中,我们首先将DashboardItemUserData表过滤为仅有问题的用户(因此我们获得了正确的用户数据,但不会破坏左联接)。
current_user = request.user
DashboardItem.objects.annotate(user_item_data=FilteredRelation('dashboarditemuserdata', condition=Q(dashboarditemuserdata__user=current_user))).order_by('user_item_data__is_favorite', 'name')