2017-02-17 2 views
0

Ich habe zwei Modelle, Post und Vote. Benutzer können Posts up- und downvoten.Django reduzieren Abfragen

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 

ich den folgenden Code in meiner Ansicht verwenden, um die Beiträge zu Vorlagen zurückzukehren:

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}) 

Das gibt nur die Beiträge , aber ich möchte auch überprüfen, ob der aktuelle Benutzer gewählt hat oder nicht (und möglicherweise die Summe der vote_type Spalte für jeden Beitrag, der die Gesamtzahl der Stimmen für den Beitrag ist).

Derzeit verwende ich Schablonen-Tags für jeden Beitrag, um zu überprüfen, ob der aktuelle Benutzer gewählt hat oder nicht. Dies erzeugt viele Anfragen. (Derzeit 50 Abfragen mit 40 Duplikaten).

Code Meines index.html Beispiel:

{% 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 %} 

Gibt es einen Weg, um alles in der views.py abzufragen und dann in der Vorlage ich so überprüfen kann: (falls post.user_voted), so dass die Datenbank wird nicht jedes Mal in der for-Schleife getroffen?

Antwort

3

Sie können prefetch_related verwenden, um die zugehörigen Abstimmungen für diesen Benutzer abzurufen.

{% if post.user_votes %} 
+0

Ist es möglich, auch für vote_type zu überprüfen:

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') ) 

Dann in Ihrer Vorlage, um den Scheck zu ändern? Hat dieser Nutzer einen Down-Vote, einen Up-Vote oder hat er nichts unternommen (vote_type = 1, -1 oder 0)? Ich meine, könnte ich die Prefetch-Abfrage ändern, um den vote_type zurückzugeben? – SMahdiS

+0

Die Prefetch-Abfrage gibt eine Liste der Stimmen zurück. Wenn Sie pro Post nur eine Stimme pro Benutzer zulassen, enthält die Liste ein Element (oder eine leere Liste, wenn der Benutzer nicht gewählt hat). Sie können den Abstimmungstyp in der Vorlage mit '{{post.user_votes.0.vote_type}}' anzeigen. – Alasdair

+0

@ Alasdair gibt es einen Weg, um die Summe der vote_type Spalte für jeden Beitrag zu erhalten, die die Gesamtzahl der Stimmen für den Beitrag ist – SMahdiS