在 django 中向 QuerySet 添加 ManyToMany 额外字段
假设我有以下模型:
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
的 Thing 对象,最多取自一个(因为我们有固定的 User)相关的评级对象。
简单的解决方案看起来像这样:
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_lated()
都不会在这里帮助我。
Suppose I have following models:
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()
So I have a lot of things, and every user can rate every thing. I also have a view showing a list of all things (and they are huge in numbers) with a rating that user assigned to each of them. I need a way to retreive all the data from database: Thing objects with additional field user_rating
taken from at most one (because we have a fixed User) related Rating object.
Trivial solution looks like that:
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
But the flaw of this approach is obvious: if we have 500 things, we'll do 501 requests to database. Per one page. Per user. And this is the most viewed page of the site. This task is easily solvable with SQL JOINs but in practice I have more complicated schema and I will certainly benefit from Django model framework. So the question is: is it possible to do this Django-way? It would be really strange if it isn't, considering that such tasks are very common.
As I understood, neither annotate()
, nor select_related()
will help me here.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想你应该尝试这个:
https://docs.djangoproject.com/en/1.3/ref/ models/querysets/#extra
示例
您的结果集为每个“事物”对象获取一个新字段“评级”。
我在最近的一个项目中使用了这种方法。它生成一个复杂的查询而不是 n+1 个查询。
希望这有帮助:)
I guess you should try this:
https://docs.djangoproject.com/en/1.3/ref/models/querysets/#extra
Example
Your result set gets a new field 'rating' for each 'thing' object.
I use this approach in one of my recent projects. It produces one complex query instead of n+1 queries.
Hope this helps :)
由于您计划在一页中显示所有内容。我能想到这个办法。您可以尝试一下:
获取当前用户给出的所有评分并获取所有事物。
现在尝试创建一个像这样的字典:
现在 thing_dict 包含模型 Thing 的所有条目作为键,并将其评级作为其值。
可能不是最好的方法。我很想看看其他人的回答。
Since you are planning to display everything in one page. I can think of this approach. You can give this a try:
Get all the ratings given by the current user and Get all the Things.
Now try to create a dictionary like this:
Now thing_dict contains all the entries of model Thing as keys and has its rating as its value.
May not be the best way. I am keen on seeing what others answer.