Tengo una lista de encuestas (preguntas) y me gustaría verificar si un User determinado ha votado en esa encuesta determinada. Aquí están mis modelos:
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_textEsta es mi opinión cuando un usuario vota en una encuesta:
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() ... Agregué un campo ManyToMany en mi modelo de Question , que después de leer los documentos, creo que es la forma correcta de vincular la lista de usuarios que votaron en una determinada pregunta, pero no estoy seguro de ser honesto. El objetivo final es poner en mi plantilla algo como: if request.user in question.has_answered: don't display the poll
¿Cómo haría exactamente esto?
Hay muchas maneras de hacerlo, preferiría crear otro modelo para votar:
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)Con esos modelos, puede contar la cantidad de votos fácilmente: y tiene la ventaja de saber qué usuario votó exactamente en la pregunta.
Choice.objects.get(pk=PK).votes.count()Para detectar si un usuario ya votó:
if Vote.objects.filter(question=1, user=user_id).count() == 1 user_id voted for question 1 alreadyPuede crear una vista de vote como esta:
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) La vista de vote anterior extraerá la identificación de la opción elegida, pero si hay un error como si no se eligiera ninguna opción, except el bloque se ejecutará e imprimirá el mensaje de error dado; de lo contrario, aumentará el recuento de votos de la opción seleccionada en 1 y lo guardará. Espero que esto te ayude.
En primer lugar, hay algunos problemas lógicos y esquemáticos que deben abordarse.
Está filtrando preguntas en función de un campo no único question_text que probablemente devuelva más de un objeto. Debe recuperar la pregunta por id :
q = Question.objects.get(pk=question) o haga que el campo question_text sea único:
question_text = models.CharField(max_length=80, unique=True) En segundo lugar, aumentar los votes en uno a través de Python puede generar condiciones de carrera que pueden ocurrir cuando dos usuarios desean aumentar los votos al mismo tiempo. Esta es la razón por la que existen objetos F en Django que le permiten hacer el incremento en el nivel de la base de datos:
from django.db.models import F def poll_answer(request): ... choice = Choice.objects.get(id=answer) choice.votes = F("votes") + 1 choice.save() ...Tengo una lista de encuestas (preguntas) y me gustaría verificar si un usuario determinado ha votado en esa encuesta determinada.
Por su diseño, no puede porque no está almacenando quién votó qué pregunta. Simplemente está incrementando el campo de votes cuando un usuario vota sobre una pregunta.
Una forma de hacerlo es cambiar el campo de votes a ManyToManyField y comenzar a almacenar los usuarios que votaron una opción:
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)para que pueda verificar si un usuario ha votado en una encuesta de la siguiente manera:
has_voted = request.user.choice_set.filter(question=question).exists() Además, me parece que la acción de votación aquí puede actuar como un modelo intermedio entre los modelos Question y User , por lo que es posible que desee ver cómo definir campos adicionales en la sección de relaciones de muchos a muchos en los documentos de Django.
Si estuviera en tu lugar, haría algo como lo siguiente:
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)