Django离开了加入m2m的领域

时间:2010-05-16 20:30:02

标签: django django-models

这是我的模特:

class User(models.Model):
    pass

class Item(models.Model):
    pass

class ItemVote(models.Model):
    user = models.ForeignKey(User)
    item = models.ForeignKey(Item)
    vote = models.BooleanField()

我想检索一个Items列表,我想知道当前用户是否已为每个Item投票。如何更改我的查询对象,以便生成类似于:

的sql
SELECT ...
FROM items
LEFT OUTER JOIN item_votes ON (item_votes.user_id = ? AND
                               item_votes.item_id = items.id)

2 个答案:

答案 0 :(得分:1)

你不能在简单的django查询中。这是一个多对多的关系,您甚至可以通过这样的方式更明确地指定它:

class Item(models.Model):
    votes = models.ManyToManyField(User, through='ItemVote', related='votedItems')

在多对多关系中,我们可以说相关集(因为有多个对象)。虽然django可以过滤相关集,例如:

Item.objects.filter(votes=request.user)

这将返回用户投票的所有项目。但是,当您在这些对象中列出.votes属性时,您将获得已投票赞成该项目的所有用户。过滤用于原始对象,从不用于相关集。

以纯粹的django方式,您可以将我以前的Item类扩展为:

class Item(models.Model):
    votes = models.ManyToManyField(User, through='ItemVote', related='votedItems')

    def markVoted(self, user):
        self.voted = user in self.votes

然后为每个对象调用此方法。但是,这将为每个对象的集合创建一个额外的查询(并且不会,select_related不适用于多对多关系)。

解决此问题的唯一方法是使用extra method向查询集添加一些SQL,如下所示:

Item.objects.extra('voted' : 'SELECT COUNT(*) FROM app_itemvote WHERE app_itemvote.item_id = app_item.id AND app_itemvote.user_id=%d'%request.user.pk)

答案 1 :(得分:0)

返回ItemVote项目:

items = ItemVote.objects.filter(user=user)

在Django模板中使用:

{% for i in items %}
item: {{ i.item }}
voted: {{ i.voted }}
{% endfor %}
相关问题