Django仿Quora应用点赞功能及按钮显示问题求助
嘿,我来帮你解决这个Quora仿站的点赞按钮问题!你现在遇到的两个核心问题:一是多用户点赞时会同时出现Upvote和Downvote按钮,二是没法高效判断当前用户是否给答案点过赞。咱们一步步来修复:
解决方案步骤
1. 先给Upvote模型加唯一约束(避免重复点赞)
首先修改models.py里的Upvote模型,加上唯一约束,确保一个用户不能给同一个答案多次点赞,同时补全Django要求的on_delete参数:
from django.contrib.auth.models import User from django.db import models from django.shortcuts import reverse class Question(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) title = models.CharField(max_length=200, blank=True, null=True) description = models.TextField() pub_date = models.DateTimeField() def __str__(self): return self.title class Answer(models.Model): answer_text = models.TextField() questions = models.ForeignKey(Question, on_delete=models.CASCADE) pub_date = models.DateTimeField(auto_now_add=True) user = models.ForeignKey(User, on_delete=models.CASCADE) def __str__(self): return self.answer_text def get_absolute_url(self): return reverse('answer:answer_by_me', kwargs={'pk': self.user.id}) class Upvote(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) answers = models.ForeignKey(Answer, on_delete=models.CASCADE) # 新增唯一约束,防止重复点赞 class Meta: unique_together = ('user', 'answers') def __str__(self): return self.user.username
2. 在Answer模型里添加判断用户点赞状态的方法
在Answer类里加一个便捷方法,让模板能直接判断当前用户是否给该答案点过赞:
class Answer(models.Model): # (保留原有字段和方法) # 新增方法:判断指定用户是否给该答案点过赞 def has_upvoted(self, user): if not user.is_authenticated: return False return self.upvote_set.filter(user=user).exists()
3. 重构模板逻辑,去掉多余循环
原来的模板遍历所有点赞记录是错误的,我们直接用上面的方法判断用户状态,只渲染一个对应按钮:
{% extends 'base.html' %} {% block title %} {{ question.title }} {% endblock %} {% block body %} <h3><i>{{ question.title }}</i></h3> {{ question.description }} {% for answer in question.answer_set.all %} <br> <div> <p>{{ answer.answer_text }} <span style="font-size: 15px">by [{{ answer.user }}]</span> </p> <form method="post" action="{% url 'answer:detail' question.id %}"> {% csrf_token %} <input type="hidden" name="type" value="vote"> <input type="hidden" name="answer_id" value="{{ answer.id }}"> {% if user.is_authenticated %} {% if answer.has_upvoted(user) %} <!-- 用户已点赞,显示取消点赞按钮 --> <input type="submit" class="btn btn-sm btn-warning" value="Downvote|{{ answer.upvote_set.count }}"> {% else %} <!-- 用户未点赞,显示点赞按钮 --> <input type="submit" class="btn btn-sm btn-success" value="Upvote|{{ answer.upvote_set.count }}"> {% endif %} {% else %} <!-- 用户未登录,显示禁用按钮提示 --> <button class="btn btn-sm btn-secondary" disabled>请登录点赞|{{ answer.upvote_set.count }}</button> {% endif %} </form> </div> {% endfor %} {% endblock %}
4. 优化查询性能(可选但推荐)
为了避免模板中每个答案调用has_upvoted时产生N+1数据库查询,我们可以在DetailView里提前预加载数据并标记点赞状态:
from django.views.generic import DetailView from .models import Question, Upvote class QuestionDetailView(DetailView): model = Question template_name = '你的模板路径.html' # 替换为实际模板路径 def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) question = self.get_object() # 提前预加载所有答案及关联的点赞记录 answers = question.answer_set.all().prefetch_related('upvote_set') if self.request.user.is_authenticated: # 获取当前用户点赞过的所有答案ID user_upvoted_ids = Upvote.objects.filter(user=self.request.user).values_list('answers__id', flat=True) # 给每个答案添加is_upvoted属性 for answer in answers: answer.is_upvoted = answer.id in user_upvoted_ids context['answers'] = answers return context
之后模板里就可以用answer.is_upvoted代替answer.has_upvoted(user),进一步提升页面加载速度。
这样修改后,每个答案只会显示一个对应状态的按钮,总票数也能正确统计,完美解决你遇到的问题!
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

