2013-11-26 79 views
1

的ManyToManyField對象我的代碼如下所示:Django的:獲取與最低組查詢

models.py

class Tag(models.Model): 
    name = models.CharField(max_length=42) 

class Post(models.Model): 
    user = models.ForeignKey(User, related_name='post') 
    #...various fields... 
    tags = models.ManyToManyField(Tag, null=True) 

views.py

posts = Post.objects.all().values('id', 'user', 'title') 
tags_dict = {} 
for post in posts: # Iteration? Why? 
    p = Post.objects.get(pk=[post['id']]) # one extra query? Why? 
    tags_dict[post['id']] = p.tags.all() 

我應該如何創建與標籤字典每個Post對象具有最少的查詢集合?是否有可能避免迭代?

回答

2

是的,你將需要一個循環。但是您可以在每次迭代中保存一個額外的查詢,您不需要獲取post對象來獲取其所有標記。您可以在Tag模式可以直接查詢來獲取標籤相關文章ID:

for post in posts: 
    tags_dict[post['id']] = Tag.objects.filter(post__id=post['id']) 

或者使用字典理解爲效率:

tags_dict = {post['id']: Tag.objects.filter(post__id=post['id']) for post in posts} 
+0

謝謝,那太棒了。它像一個魅力!請您在查找時間將「標籤」更改爲「標籤」。 :-) – xpanta

+0

感謝您指出。我已將其重命名爲「Tag」。不用謝。 –

1

如果你有Django的版本> = 1.4,並不真正需要一本字典,但需要削減查詢數,你可以使用this method這樣的:

posts = Post.objects.all().only('id', 'user', 'title').prefetch_related('tags') 

它似乎只執行2查詢(一爲Post和另一個用於具有INNER JOIN的Tag)。

然後,您可以訪問post.tags.all而無需額外查詢,因爲標籤已被預取。

{% for post in posts %} 
    {% for tag in post.tags.all %} 
     {{ tag.name }} 
    {% endfor %} 
{% endfor %}