Джанго - Пользователь должен иметь возможность голосовать только один раз
Я хочу, чтобы пользователь мог голосовать только один раз за запрос категории, но каким-то образом я получаю следующую ошибку, и я не знаю, как "правильно" вызвать экземпляр в этот момент:
Невозможно присвоить "1": "CategoryRequests_Voter.voted" должен быть экземпляром "CategoryRequests".
models.py
# Category Requests Model
class CategoryRequests(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
....
# Vote(s) of Category Requests Model
class CategoryRequests_Voter(models.Model):
voter = models.ForeignKey(User, on_delete=models.CASCADE)
voted = models.ForeignKey(CategoryRequests, on_delete=models.CASCADE)
published_date = models.DateField(auto_now_add=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
views.py
def category_request_up_vote (request, pk):
category_request = get_object_or_404(CategoryRequests, pk=pk)
if request.method == 'GET':
if CategoryRequests_Voter.objects.filter(voter=request.user, voted=category_request.pk).exists():
messages.error(request, 'You already voted for this request.')
else:
category_request.up_vote = F('up_vote') + 1
category_request.save()
CategoryRequests_Voter.objects.create(voter=request.user, voted=category_request.pk)
messages.success(request, 'You have successfully Provided an Up-Vote for this Request')
return redirect('category_request_detail', pk=category_request.pk)
else:
messages.error(request, 'Uuups, something went wrong, please try again.')
return redirect('category_request_detail', pk=category_request.pk)
заранее спасибо
2 ответа
Вам нужно исправить voted
аргумент просто category_request
, а не его первичный ключ, как:
CategoryRequests_Voter.objects.create(voter=request.user, voted=category_request)
Однако вы можете улучшить свою модель и внешний вид, чтобы улучшить согласованность и элегантность. Чтобы предотвратить User
от голосования дважды или более, вы можете предотвратить создание CategoryRequest_Voter
объект дважды для одного и того же voter
а также voted
, используя unique_together
ограничение:
class CategoryRequests_Voter(models.Model):
voter = models.ForeignKey(User, on_delete=models.CASCADE)
voted = models.ForeignKey(CategoryRequests, on_delete=models.CASCADE)
published_date = models.DateField(auto_now_add=True, null=True)
class Meta:
unique_together = ('voter', 'voted')
def publish(self):
self.published_date = timezone.now()
self.save()
Кроме того, мы можем использовать get_or_create
и, таким образом, сделать только одну выборку из базы данных. Обычно представление, которое изменяет данные, должно делать это с запросом POST, а не с GET. Запросы GET не должны иметь побочных эффектов.
def category_request_up_vote (request, pk):
category_request = get_object_or_404(CategoryRequests, pk=pk)
if request.method == 'POST':
__, created = CategoryRequests_Voter.objects.get_or_create(
voter=request.user,
voted=category_request
)
if created:
category_request.up_vote = F('up_vote') + 1
category_request.save()
messages.success(request, 'You have successfully Provided an Up-Vote for this Request')
else:
messages.error(request, 'You already voted for this request.')
else:
messages.error(request, 'Uuups, something went wrong, please try again.')
return redirect('category_request_detail', pk=category_request.pk)
Возможно, стоит посчитать количество CategoryRequest_Voter
s, вместо увеличения подсчета голосов, поскольку возможно, что, например, из-за удаления User
s, или голосов, в конечном итоге количество голосов больше не согласуется с количеством CategoryRequests_Voter
для этого CategoryRequests
объект.
Возможно, подсчет количества объектов не так эффективен для каждого голоса, но вы можете сделать задачу, которая запускается время от времени, и таким образом вычислить:
CategoryRequests_Voter.objects.filter(voted=category_request).count()
посчитать количество CategoryRequests_Voter
для данного category_request
,
def category_request_up_vote (request, pk):
category_request = get_object_or_404(CategoryRequests, pk=pk)
try:
if request.method == 'GET':
if CategoryRequests_Voter.objects.filter(voter=request.user, voted=category_request).exists():
messages.error(request, 'You already voted for this request.')
return redirect('category_request_detail', pk=category_request.pk)
else:
category_request.up_vote = F('up_vote') + 1
category_request.save()
CategoryRequests_Voter.objects.create(voter=request.user, voted=category_request)
messages.success(request, 'You have successfully Provided an Up-Vote for this Request')
return redirect('category_request_detail', pk=category_request.pk)
else:
messages.error(request, 'Uuups, something went wrong, please try again.')
return redirect('category_request_detail', pk=category_request.pk)
except:
messages.error(request, 'Uuups, something went wrong, please try again.')
return redirect('category_request_detail', pk=category_request.pk)