Bootstrap

如何检查列表中的某个帖子是否被当前用户投票

在 Django 项目中,如果需要检查一个列表中的某个帖子是否被当前用户投票(比如点赞或踩),可以通过数据库查询实现。以下是具体的实现方法,假设你使用的是 Django 并有如下的数据库模型结构:

在这里插入图片描述

问题背景

我正在创建一个reddit克隆,其中存在一个问题,我正在寻找一种方法来指示当前用户是否对某个特定问题进行过投票,而不会产生过多数据库请求。

我的模型如下:

class Thread(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField(max_length=max_post_length)
    created = models.DateField()
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    userUpVotes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='threadUpVotes')
    userDownVotes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='threadDownVotes')

    def __str__(self):
        return self.title


class Comment(MPTTModel):
    title = models.CharField(max_length=200)
    text = models.TextField(max_length=max_post_length)
    created = models.DateField()
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    thread = models.ForeignKey(Thread)
    parent = TreeForeignKey('self', related_name='children', blank=True, null=True)
    vote_count = models.IntegerField(default=0)
    userUpVotes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='commentUpVotes')
    userDownVotes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='commentDownVotes')

    class MPTTMeta:
        order_insertion_by = ['created']

    def save(self, *args, **kwargs):
        self.vote_count = self.userUpVotes.count() - self.userDownVotes.count()
        super(Comment, self).save(*args, **kwargs)

    def __str__(self):
        return self.title

我的视图如下:

from django.shortcuts import get_object_or_404, render
from community.models import Thread, Comment
from django.http import HttpResponse


def detail(request, thread_id):
    thread = get_object_or_404(Thread, pk=thread_id)
    comments = thread.comment_set.all()

    return render(request, 'threads/detail.html', {
        'thread': thread,
        'comments': comments
    })

我的模板如下:

{% extends "base.html" %}
{% load mptt_tags %}
{% block content %}
    <h1>{{ thread.title }}</h1>
    <p>{{ thread.text }}</p>
    <ul class="comments">
        {% recursetree comments %}
            <li>
                <div class="comment-block clearfix">
                    <vote-up-down up="{{ node.up_vote_by_user }}"
                                  down="{{ node.user_down_vote }}"
                                  url="/community/comment/{{ node.id }}/vote/"
                                  count="{{ node.vote_count }}"></vote-up-down>
                    <div class="comment">
                        <h4>{{ node.title }}</h4>

                        <div class="text">{{ node.text }}</div>
                    </div>
                </div>
                {% if not node.is_leaf_node %}
                    <ul class="children">
                        {{ children }}
                    </ul>
                {% endif %}
            </li>
        {% endrecursetree %}
    </ul>
{% endblock content %}

解决方案

对于这种问题,通常有两种解决方案:

1、通过模型方法

首先,我们需要在模型中添加两个方法,用来检查用户是否对某个节点进行过投票。

class Node(models.Model):
    ...

   def upvoted_by(self, user):
       return self.up_votes.filter(user=user).exists()

   def downvoted_by(self, user):
       return self.down_votes.filter(user=user).exists()

然后,在视图中,我们可以使用这些方法来检查用户是否对某个帖子进行过投票。

def detail(request, thread_id):
    thread = get_object_or_404(Thread, pk=thread_id)
    comments = thread.comment_set.all()

    for comment in comments:
        comment.up_voted_by_user = comment.upvoted_by(request.user)
        comment.down_voted_by_user = comment.downvoted_by(request.user)

    return render(request, 'threads/detail.html', {
        'thread': thread,
        'comments': comments
    })

最后,在模板中,我们可以使用这些变量来显示投票信息。

{% extends "base.html" %}
{% load mptt_tags %}
{% block content %}
    <h1>{{ thread.title }}</h1>
    <p>{{ thread.text }}</p>
    <ul class="comments">
        {% recursetree comments %}
            <li>
                <div class="comment-block clearfix">
                    <vote-up-down up="{{ node.up_voted_by_user }}"
                                  down="{{ node.down_voted_by_user }}"
                                  url="/community/comment/{{ node.id }}/vote/"
                                  count="{{ node.vote_count }}"></vote-up-down>
                    <div class="comment">
                        <h4>{{ node.title }}</h4>

                        <div class="text">{{ node.text }}</div>
                    </div>
                </div>
                {% if not node.is_leaf_node %}
                    <ul class="children">
                        {{ children }}
                    </ul>
                {% endif %}
            </li>
        {% endrecursetree %}
    </ul>
{% endblock content %}

2、通过数据库查询

def detail(request, thread_id):
    thread = get_object_or_404(Thread, pk=thread_id)
    comments = thread.comment_set.all()

    upvoted_comments = request.user.comment_upvotes.filter(
        id__in=comments).values_list('pk', flat=True)

    downvoted_comments = request.user.comment_downvotes.filter(
        id__in=comments).exclude(
        id__in=upvoted_comments).values_list('pk', flat=True)

    return render(request, 'threads/detail.html', {
        'thread': thread,
        'comments': comments,
        'upvoted_comments': set(upvoted_comments),
        'downvoted_comments': set(downvoted_comments)
    })

最后,在模板中,我们可以使用这些变量来显示投票信息。

{% extends "base.html" %}
{% load mptt_tags %}
{% block content %}
    <h1>{{ thread.title }}</h1>
    <p>{{ thread.text }}</p>
    <ul class="comments">
        {% recursetree comments %}
            <li>
                <div class="comment-block clearfix">
                    <vote-up-down up="{%if node.pk in upvoted_comments %}{% endif %}"
                                  down="{%if node.pk in downvoted_comments %}{% endif %}"

  ...

通过上述方法,可以高效地检查列表中每个帖子是否被当前用户投票,并优化查询性能。

;