2017-02-17 114 views
0

我有两个模型,Post和Vote。用户可以upvote和downvote帖子。Django减少查询

models.py:

class Post(models.Model): 
    poster = models.ForeignKey('auth.User') 
    question = models.ForeignKey('self', null=True, blank=True) 
    post_title = models.CharField(max_length=300) 
    post_content = models.TextField(null=True, blank=True) 

    is_published = models.BooleanField(default=True) 
    is_locked = models.BooleanField(default=False) 
    is_question = models.BooleanField(default=True) 
    is_deleted = models.BooleanField(default=False) 

    created_date = models.DateTimeField(
      default=timezone.now) 
    published_date = models.DateTimeField(
      blank=True, null=True) 
    date_modified = models.DateTimeField(
      blank=True, null=True) 

    def publish(self): 
     self.published_date = timezone.now() 
     self.save() 

    def __str__(self): 
     return self.post_title 

class Vote(models.Model): 
    user = models.ForeignKey('auth.User') 
    post = models.ForeignKey('Post') 
    vote_type = models.SmallIntegerField()#-1, 0, 1 
    date_voted = models.DateTimeField(
      default=timezone.now) 
    def __str__(self): 
     return self.user 

我用下面的代码在我看来,在帖子返回模板:

views.py:

def index(request): 
    posts = Post.objects.filter(created_date__lte=timezone.now(
    ), is_question=1, is_published=1).order_by('-created_date') 
    #removed the paging stuff here for simplification 
    return render(request, 'homepage/index.html', {'posts': posts}) 

这只是返回岗位,但我也想检查当前用户是否投了票(也可能是每个帖子的vote_type列的总和,即该帖子的总投票数)。

目前我使用每个帖子的模板标签来检查当前用户是否投了票。这会产生很多查询。 (目前有40个重复的50个查询)。

我的index.html的示例代码:

{% for post in posts %} 
     {% if post|userVotedThisPost:request.user.id == 1 %} 
       <img id="upvote-img" class="icons" src="{% static 'img/upvote-marked.svg' %}" alt="Upvote"> 
     {% else %} 
       <img id="upvote-img" class="icons" src="{% static 'img/upvote.svg' %}" alt="Upvote"> 
     {% endif %} 
{% endfor %} 

有什么办法来查询在views.py一切,然后在模板我可以检查这样的:(如果post.user_voted),使每次在for循环中数据库都不会被命中?

回答

3

您可以使用prefetch_related获取该用户的相关投票。

from django.db.models import Prefetch 

Post.objects.filter(
    created_date__lte=timezone.now(), 
    is_question=1, 
    is_published=1 
).order_by(
    '-created_date', 
).prefetch_related(
    Prefetch('vote_set', queryset=Vote.objects.filter(user=request.user), to_attr='user_votes') 
) 

然后在你的模板,改变检查:

{% if post.user_votes %} 
+0

是否有可能检查vote_type呢?这个用户是否已经投票,投票或者什么都没做(vote_type = 1,-1或者0)?我的意思是我可以更改预取查询返回vote_type? – SMahdiS

+0

预取查询返回一列选票。如果您只允许每个用户每个帖子投一票,那么该列表将包含一个项目(或者如果用户未投票,则该列表将为空列表)。您可以使用'{{post.user_votes.0.vote_type}}'在模板中显示投票类型。 – Alasdair

+0

@ Alasdair是否有某种方式可以获得每个帖子的vote_type列的总和,即该帖子的总投票数 – SMahdiS