在Django中不修改第三方django-contrib-comments架构,如何关联评论用户的Poller投票记录?
解决方案:无需修改第三方库,通过关联查询获取用户投票记录
完全理解你的需求——不想碰django-contrib-comments的代码,只想在自己的视图和模板里搞定评论与对应投票的展示。其实不用子类化CommentAbstractModel,咱们通过关联查询预取就能完美解决这个问题,具体步骤如下:
第一步:给Vote模型加唯一性约束(可选但强烈推荐)
首先,为了确保一个用户对同一个Poller只能投一次票,先在Vote模型的Meta类里加个联合唯一约束,避免后续出现一个用户多条投票记录的混乱:
class Vote(models.Model): poller = models.ForeignKey(Poller, on_delete=models.CASCADE, related_name='vote') user = models.ForeignKey(Account, on_delete=models.CASCADE) created_on = models.DateTimeField(auto_now_add=True) poller_choice_one_vote = models.BooleanField(default=False) poller_choice_two_vote = models.BooleanField(default=False) class Meta: # 确保一个用户对一个Poller只能有一条投票记录 unique_together = ('poller', 'user')
第二步:在single_poller视图中预取评论与对应投票
接下来修改你的视图,获取当前Poller的所有评论,同时通过Prefetch精准预取每个评论用户针对该Poller的投票记录。这样可以避免N+1查询问题,性能更优:
先导入需要的模块:
from django.contrib.comments.models import Comment from django.contrib.contenttypes.models import ContentType from django.db.models import Prefetch
然后更新视图代码:
@require_GET def single_poller(request, poller_id): """ renders a specific poller with prepopulated meta according to previous user interaction, e.g. votes and likes """ # Retrieve the item via get poller = Poller.objects.get(poller_id=poller_id) # 获取当前Poller对应的ContentType(django-contrib-comments用这个关联目标模型) poller_ct = ContentType.objects.get_for_model(Poller) # 获取该Poller下的所有评论,同时预取每个评论用户的对应投票 comments = Comment.objects.filter( content_type=poller_ct, object_pk=str(poller.poller_id) # 因为主键是UUID,要转成字符串匹配Comment的object_pk字段 ).prefetch_related( # 预取评论用户针对当前Poller的投票,存到poller_vote属性里 Prefetch( 'user__vote', queryset=Vote.objects.filter(poller=poller), to_attr='poller_vote' ) ) # 把poller和comments传到模板 context = { 'poller': poller, 'comments': comments, # 其他你需要的上下文变量... } return render(request, 'your_template.html', context)
第三步:在模板中渲染评论与投票信息
现在模板里就能直接拿到每个评论用户的投票记录了,因为我们已经把投票预取到了comment.user.poller_vote里(因为加了unique约束,这个列表里最多只有一个元素):
{% for comment in comments %} <div class="comment-card"> <h4>{{ comment.user.username }}</h4> <p class="comment-content">{{ comment.comment }}</p> {% with user_vote=comment.user.poller_vote.0 %} {% if user_vote %} <p class="vote-info"> 该用户投票选择: {% if user_vote.poller_choice_one_vote %} 选项一 {% elif user_vote.poller_choice_two_vote %} 选项二 {% endif %} </p> {% else %} <p class="vote-info">该用户未参与此投票</p> {% endif %} {% endwith %} </div> {% endfor %}
为什么不用子类化CommentAbstractModel?
因为你的Comment模型(不管是默认的还是自定义的子类)已经通过user字段关联到了Account,而Vote同时关联了Account和Poller——这就形成了Comment -> User -> Vote <- Poller的关联链,通过预取关联查询完全可以拿到需要的数据,根本不需要修改第三方库的模型结构,完美符合你的需求。
内容的提问来源于stack exchange,提问作者JSRB
相关产品推荐
相关产品推荐

