2017-04-15 2 views
2

Ich habe eine Liste von Umfragen (Fragen) und würde gerne prüfen, ob ein bestimmter User über diese bestimmte Umfrage abgestimmt hat. Hier ist meine Modelle:Überprüfen, ob der Benutzer bei einer bestimmten Umfrage abgestimmt hat

class Question(models.Model): 
    has_answered = models.ManyToManyField(User) 
    question_text = models.CharField(max_length=80) 

    def __str__(self): 
     return self.question_text 

class Choice(models.Model): 
    question = models.ForeignKey(Question, on_delete=models.CASCADE) 
    choice_text = models.CharField(max_length=100) 
    votes = models.IntegerField(default=0) 

    def __str__(self): 
     return self.choice_text 

hier meiner Meinung nach ist, wenn ein Benutzer Stimmen für eine Umfrage:

def poll_answer(request): 
    if request.method == 'POST': 
     answer = request.POST.get('answer') 
     question = request.POST.get('question') 

     q = Question.objects.get(question_text=question) 

     choice = Choice.objects.get(id=answer) 
     choice.votes += 1 
     choice.save() 
     ... 

Ich habe ein ManyToMany Feld in meinem Question Modell hinzugefügt, die nach der docs lesen Ich glaube, das ist richtiger Weg, um die Liste der Benutzer zu verknüpfen, die über eine bestimmte Frage abgestimmt haben, aber ich bin mir nicht sicher, um ehrlich zu sein. Das Endziel ist, in meine Vorlage so etwas wie zu setzen: if request.user in question.has_answered: don't display the poll

Wie genau würde ich darüber gehen?

Antwort

0

Zunächst einmal gibt es einige logische und schematische Probleme, die angesprochen werden müssen.

Sie filtern Fragen basierend auf einem nicht eindeutigen Feld question_text, das wahrscheinlich mehr als ein Objekt zurückgibt. Sie sollten entweder abrufen, die Frage nach id:

q = Question.objects.get(pk=question) 

oder question_text Gebiet einzigartig machen:

question_text = models.CharField(max_length=80, unique=True) 

Zweitens kann race conditionsvotes durch eine über Python Inkrementieren führen, die auftreten können, wenn zwei Benutzer erhöhen möchten Stimmen zur gleichen Zeit. Aus diesem Grund gibt es F Objekte in Django mit dem Sie den Zuwachs in Datenbankebene tun:

from django.db.models import F 

def poll_answer(request): 
    ... 
    choice = Choice.objects.get(id=answer) 
    choice.votes = F("votes") + 1 
    choice.save() 
    ... 

ich eine Liste von Umfragen (Fragen) haben, und würde überprüfen möchten, ob ein bestimmter Benutzer hat stimmte über diese bestimmte Abstimmung ab.

Mit Ihrem Design, können Sie nicht weil Sie speichern nicht, wer auf welche Frage gestimmt.Sie erhöhen nur votes Feld, wenn ein Benutzer über eine Frage abstimmt.

Eine Möglichkeit, das zu tun, können Sie votes Feld ManyToManyField ändern und starten Benutzer zu speichern, die auf einer Wahl eine Abstimmung gestellt haben:

class Question(models.Model): 
    text = models.CharField(max_length=80, unique=True) 

    def __str__(self): 
     return self.text 

class Choice(models.Model): 
    question = models.ForeignKey(Question) 
    choice = models.CharField(max_length=100) 
    votes = models.ManyToMany(User) 

so können Sie überprüfen, ob ein Benutzer für eine Umfrage abgestimmt hat als folgt: Des Weiteren

has_voted = request.user.choice_set.filter(question=question).exists() 

, so scheint es mir, dass die Abstimmung Aktion hier kann wie ein Zwischenmodell wirken zwischen Question und User Modelle, so dass Sie einen Blick aufnehmen möchtenAbschnitt in Django docs.

Wenn ich an deiner Stelle wäre, würde ich so etwas wie unten tun:

class Question(models.Model): 
    text = models.CharField(max_length=80, unique=True) 
    voters = models.ManyToManyField(User, through="Vote") 

class Choice(models.Model): 
    question = models.ForeignKey(Question) 
    text = models.CharField(max_length=100) 

class Vote(models.Model): 
    question = models.ForeignKey(Question, on_delete=models.CASCADE) 
    user = models.ForeignKey(User, on_delete=models.CASCADE) 
    choice = models.ForeignKey(Choice, on_delete=models.CASCADE) 
    voted_at = models.DateTimeField(auto_now_add=True) 
0

Es gibt viele Möglichkeiten, das zu tun, würde ich ein anderes Modell für eine Abstimmung erstellen bevorzugen:

class Vote(models.Model): 
    user = models.ForeignKey(User, unique=True) 

class Choice(models.Model): 
    question = models.ForeignKey(Question, related_name='choices') 
    choice_text = models.CharField(max_length=100) 
    votes = models.ForgeinKey(Vote) 

Mit, dass Modelle, die Sie die Anzahl der Stimmen leicht zählen können: Und Sie haben den Vorteil, wissen, was genau User stimmten für die Frage

Choice.objects.get(pk=PK).votes.count() 

zu erkennen, ob ein Benutzer bereits abgestimmt:

if Vote.objects.filter(question=1, user=user_id).count() == 1 
user_id voted for question 1 already 
0

Sie können eine vote Ansicht wie folgt erstellen:

def vote(request, question_id): 
    question = get_object_or_404(Question, pk=question_id) 
    try: 
     selected_choice = question.choice_set.get(pk=request.POST['choice']) 
    except: 
     return render(request, 'your_question_page.html', {'question': question, 
      'error_message': "Please select an option"}) 
    else: 
     selected_choice.votes += 1 
     selected_choice.save() 

     return redirect('polls:result_page_view', question_id=question_id) 

Die oben vote Ansicht die Option ID der gewählten Option extrahieren, aber wenn es einen Fehler wie keine gewählte Option dann wird except Block ausführen und die Druck Eine Fehlermeldung wird angezeigt, andernfalls wird die Anzahl der Stimmen der ausgewählten Option um 1 erhöht und gespeichert. Hoffe das hilft dir.

Verwandte Themen