在Django中将ManyToMany额外字段添加到QuerySet

时间:2012-01-06 16:57:52

标签: django model many-to-many

假设我有以下模型:

class Thing(models.Model):
    name = models.CharField(max_length=100)
    ratings = models.ManyToManyField('auth.User', through='Rating')

class Rating(models.Model):
    user = models.ForeignKey('auth.User')
    thing = models.ForeignKey('Thing')
    rating = models.IntegerField()

所以我有很多东西,每个用户都可以评价每一件事。我还有一个视图显示所有事物的列表(并且它们的数量很大),其中包含用户分配给每个事物的评级。我需要一种方法来检索数据库中的所有数据:具有附加字段user_rating的对象最多取自一个(因为我们有一个固定的用户)相关的评级对象。

琐碎的解决方案看起来像这样:

things = Thing.objects.all()
for thing in things:
    try:
        thing.user_rating = thing.ratings.objects.get(user=request.user).rating
    except Rating.DoesNotExist:
        thing.user_rating = None

但这种方法的缺陷是显而易见的:如果我们有500件事,我们会对数据库做501请求。每页一页。每个用户。这是该网站浏览量最高的页面。使用SQL JOIN可以很容易地解决这个任务,但实际上我有更复杂的模式,我一定会受益于Django模型框架。所以问题是:是否可以这样做Django方式?如果不是这样,那将是非常奇怪的,因为这些任务非常普遍。

据我了解,annotate()select_related()都无法帮助我。

2 个答案:

答案 0 :(得分:3)

我想你应该试试这个: https://docs.djangoproject.com/en/1.3/ref/models/querysets/#extra

实施例

result = Thing.objects.all().extra(select={'rating': 'select rating from ratings where thing_id = id'})

您的结果集会为每个“事物”对象获取一个新字段“评级”。

我在最近的一个项目中使用这种方法。它生成一个复杂的查询而不是n + 1个查询。

希望这会有所帮助:)

答案 1 :(得分:0)

因为您计划在一个页面中显示所有内容。我能想到这种方法。你可以尝试一下:

获取当前用户提供的所有评分并获取所有内容。

现在尝试创建一个这样的字典:

thing_dict = {}

for thing in Thing.objects.all():
    thing_dict[thing] = None
for rating in Rating.objects.filter(user = request.user):
    thing_dict[rating.thing] = rating

现在,thing_dict包含模型Thing作为键的所有条目,并将其评级作为其值。

可能不是最好的方法。我很想知道其他人的回答。