Django模型中的“多对多”关系查询集的输出错误

时间:2012-08-06 10:23:49

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

我有以下Django模型:

class User(models.Model):
    username = models.CharField(max_length=50, unique=True)
    name = models.CharField(max_length=100)

class Url(models.Model):
    user = models.ManyToManyField(User)
    url = models.URLField()

class Keywords(models.Model):
    url = models.ManyToManyField(Url)
    keyword = models.CharField(max_length=100)

现在,我想要数据库中任何两个用户的所有常用关键字:

username1 = 'user1'
username2 = 'user2'

尝试1:

Keyword.objects.filter(url__user__username=username1).filter(url__user__username=username2).values('keyword', 'url__url').distinct()

// Returns empty list []   [ Wrong ]

尝试2:

k1 = [ k.keyword for k in Keyword.objects.filter(url__user__username=username1) ]
k2 = [ k.keyword for k in Keyword.objects.filter(url__user__username=username2) ]

common_k = list(set(k1).intersection(set(k2)))
print common_k

// Return list of common keys (As Expected) [ Correct ]

我在尝试1时做错了什么?

请注意:首先.filter(url__user__username=username1).filter(url__user__username=username2)似乎有误,但它有多对多关系,应该可以正常工作。

尝试1的测试输入

newuser1 = User.objects.get(username='newuser1')
newuser2 = User.objects.get(username='newuser2')

url = Url(url='http://common.com/')
url.save()
url.user.add(newuser1)
url.user.add(newuser2)

key = Keyword(keyword='common')
key.save()
key.url.add(url)

现在,我尝试了尝试1和尝试2,并按预期得到了正确的结果。我将common作为newuser1newuser2的关键字。

现在,尝试2肯定是正确的,那么我在尝试1时做错了什么?

3 个答案:

答案 0 :(得分:2)

Attempt1 正在将网址过滤到名称为username1的用户,然后将该查询的结果过滤给名称为username2的用户。但是第一个列表只能包含那些带有username1的列表,因此第二个过滤器的结果将始终为空。

但是,您可以在 Attempt2 中找到这两个查询之间的交集,而不是按顺序应用它们。这是完全不同的,并将给出正确的答案。

您可以将此方法添加到您的用户类,以便您可以执行user1.commonKeywordsWithUser(user2),即

class User(models.Model):
    username = models.CharField(max_length=50, unique=True)
    name = models.CharField(max_length=100)

    def commonKeywordsWithUser(user):
        k1 = [ k.keyword for k in Keyword.objects.filter(url__user__username=self.name) ]
        k2 = [ k.keyword for k in Keyword.objects.filter(url__user__username=user.name) ]

        return list(set(k1).intersection(set(k2)))

答案 1 :(得分:0)

set_1 = set(Keyword.objects.filter(url__user__username=username1).values_list('keyword'))
set_2 = set(Keyword.objects.filter(url__user__username=username2).values_list('keyword'))
common_keywords = list(set_1 & set_2)

单一查询解决方案:

from django.db.models import Q
Keyword.objects.filter(url__user__username=username1).exclude(~Q(url__user__username=username2)).values('keyword', 'url__url').distinct()

使用单个查询的解决方案(来自2个用户的不同网址导致相同的关键字未被删除):

from django.db.models import Q
Keyword.objects.filter(url__user__username=username1).exclude(~Q(url__user__username=username2)).values('keyword', 'url__url').distinct('keyword', 'url__url')

答案 2 :(得分:0)

您可以尝试以下内容(针对尝试1):

Keyword.objects.filter(url__user__username=username1, keyword__in=Keyword.objects.filter(url__user__username=username2).values_list('keyword', flat=True)).values_list('keyword', flat=True).distinct()