Модель голосования, вызывающая неизвестные проблемы - PullRequest
0 голосов
/ 26 сентября 2019

Я сделал модель голосования, приведенную ниже.Моя модель блога имеет две операции, которые повышают или понижают определенный блог.Например, когда один пользователь голосует против, поле голосов в блоге увеличивается, и у модели UserVote есть запись об этом, а когда тот же пользователь понижает голос, он меняет свой тип_оценки и обновляет запись.

Проблема возникаеткогда второй пользователь голосует.После отрицательного голоса, когда второй пользователь отрицает голос, он говорит, что он уже проголосовал (хотя он должен был изменить его voice_type на downvote)

Я прошел через эту проблему и не могу найтирешение его где угодно.

class Blog(models.Model):
title = models.CharField(max_length=100, blank=True, default='')
description = models.TextField(max_length=1500)
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey('auth.User', related_name='blog', on_delete=models.CASCADE, null=True)
image = models.FileField(blank=True, null=True)
votes = models.IntegerField(default=0)

def upvote(self, user):
    try:
        if UserVote.objects.filter(user=user, blog=self, vote_type='down').exists():
            self.post_votes.update(user=user, blog=self, vote_type='up')
            self.votes += 2

        else:
            self.post_votes.create(user=user, blog=self, vote_type='up')
            self.votes += 1

        self.save()

    except IntegrityError:
        return 'already_voted'

    return 'ok'

def downvote(self, user):
    try:
        if UserVote.objects.filter(user=user, blog=self, vote_type='up').exists():
            self.post_votes.update(user=user, blog=self, vote_type='down')
            self.votes -= 2

        else:
            self.post_votes.create(user=user, blog=self, vote_type='down')
            self.votes -= 1

        self.save()

    except IntegrityError:
        return 'already_voted'

    return 'ok'

class UserVote(models.Model):
user = models.ForeignKey('auth.User', related_name='user_votes', on_delete=models.CASCADE)
blog = models.ForeignKey(Blog, related_name='post_votes', on_delete=models.CASCADE)
vote_type = models.CharField(max_length=10)

class Meta:
    unique_together = ('user', 'blog', 'vote_type')

1 Ответ

0 голосов
/ 26 сентября 2019

Проблема возникает из-за того, что у вас может быть один объект UserVote на комбинацию User / Blog / VoteType.

В частности, в следующих строках

self.post_votes.update(user=user, blog=self, vote_type='up')

self.post_votes.update(user=user, blog=self, vote_type='down')

вы пытаетесьобновите все объекты голосования, существующие для текущего блога, до одного из voice_types.Это означает, что вы потенциально можете попытаться изменить два UserVotes, чтобы иметь одного и того же пользователя, blog и voice_type, что вызывает IntegrityError.

Таким образом, я бы предложил использовать только одно UserVote на комбинацию User / Blog вместо каждойКомбинация User / Blog / VoteType, то есть измените unique_together на

unique_together = ('user', 'blog')

Затем вам просто нужно изменить тип голосования, если пользователь уже проголосовал в этом блоге.Это предотвращает одновременное повышение и понижение голосов одного и того же пользователя для одного и того же блога.

Кроме того, вам не нужно вручную отслеживать общее количество положительных и отрицательных голосов, вы можете получить их прямо изколичество объектов UserVote.Мой предложенный models.py выглядит примерно так:

from django.db import models


class Blog(models.Model):
    title = models.CharField(max_length=100, blank=True, default='')
    description = models.TextField(max_length=1500)
    created = models.DateTimeField(auto_now_add=True)
    owner = models.ForeignKey('auth.User', related_name='blog', on_delete=models.CASCADE, null=True)
    image = models.FileField(blank=True, null=True)

    @property
    def votes(self):
        upvotes = UserVote.objects.filter(blog=self, vote_type='up').count()
        downvotes = UserVote.objects.filter(blog=self, vote_type='down').count()
        return upvotes - downvotes

    def upvote(self, user):
        vote, created = UserVote.objects.get_or_create(user=user, blog=self)
        if not created and vote.vote_type == 'up':
            return 'already_voted'
        vote.vote_type = 'up'
        vote.save()
        return 'ok'

    def downvote(self, user):
        vote, created = UserVote.objects.get_or_create(user=user, blog=self)
        if not created and vote.vote_type == 'down':
            return 'already_voted'
        vote.vote_type = 'down'
        vote.save()
        return 'ok'


class UserVote(models.Model):
    user = models.ForeignKey('auth.User', related_name='user_votes', on_delete=models.CASCADE)
    blog = models.ForeignKey(Blog, related_name='post_votes', on_delete=models.CASCADE)
    vote_type = models.CharField(max_length=10)

    class Meta:
        unique_together = ('user', 'blog')

Я уверен, что есть гораздо более умный способ получить общее количество положительных и отрицательных голосов, используя агрегации , это простобыстрый рабочий пример.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...