【问题标题】:Django ORM query for friends of a userDjango ORM查询用户的朋友
【发布时间】:2012-04-17 10:12:08
【问题描述】:

我无法让 Django ORM 查询正常工作。我有这个友谊模型:

class Friendship(models.Model):
    user1 = models.ForeignKey(User, related_name='friendships1')
    user2 = models.ForeignKey(User, related_name='friendships2')
    class Meta:
        unique_together = ('user1', 'user2',)

要查找给定用户的朋友,我们必须检查 user1 和 user2,因为我们永远无法确定他们将处于关系的哪一边。因此,要获取给定用户的所有朋友,我使用以下查询:

user = request.user
User.objects.filter(
    Q(friendships1__user2=user, friendships1__status__in=statuses) |
    Q(friendships2__user1=user, friendships2__status__in=statuses)
)

在我看来,它应该可以工作,但事实并非如此。它给了我重复。这是它生成的 SQL:

SELECT auth_user.*
FROM auth_user
LEFT OUTER JOIN profile_friendship ON (auth_user.id = profile_friendship.user1_id)
LEFT OUTER JOIN profile_friendship T4 ON (auth_user.id = T4.user2_id)
WHERE (
    (profile_friendship.status IN ('Accepted') AND profile_friendship.user2_id = 1 )
    OR (T4.user1_id = 1 AND T4.status IN ('Accepted'))
);

这是我想要的 SQL,它会产生正确的结果:

SELECT f1.id as f1id, f2.id AS f2id, u.*
FROM auth_user u
LEFT OUTER JOIN profile_friendship f1 ON (u.id = f1.user1_id AND f1.user2_id = 1 AND f1.status IN ('Accepted'))
LEFT OUTER JOIN profile_friendship f2 ON (u.id = f2.user2_id AND f2.user1_id = 1 AND f2.status IN ('Accepted'))
WHERE f1.id IS NOT NULL OR f2.id IS NOT NULL

我知道我可以在原始查询中执行此操作,但我认为我无法链接。有没有一种很好的干净的方法来做到这一点而不会生硬?

【问题讨论】:

    标签: django django-models orm


    【解决方案1】:

    【讨论】:

    • 他需要存储额外的信息,好像不行。
    • @santiagobasulto 或为 M2M 指定 through table
    • @santiagobasulto 的解决方案对我有用。但是,我想知道这个解决方案是否会更简单一些,甚至可以更好地工作,只要我仍然可以指定一个直通表。但是,我不清楚如何在对称关系中做到这一点。我现在正在努力解决这个问题......
    • 确认这种方法不允许我指定一个直通表。错误:一个或多个模型未验证:accounts.profile:具有中间表的多对多字段不能对称。
    【解决方案2】:

    简单的解决方案:

    user = request.user
    User.objects.filter(
        Q(friendships1__user2=user, friendships1__status__in=statuses) |
        Q(friendships2__user1=user, friendships2__status__in=statuses)
    ).distinct()
    

    有人知道有什么缺点吗?

    【讨论】:

    • 我对此进行了测试,它可以工作。就我个人而言,我不会完全按照 ORM 的方式编写查询,但它似乎仍然表现得相当好。这里唯一的缺点是使用未包含在结果集中的字段可能会出现重复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-16
    • 1970-01-01
    • 2019-10-08
    相关资源
    最近更新 更多