【问题标题】:How to check if some post was voted for by the current user in a list如何检查某个帖子是否被列表中的当前用户投票
【发布时间】:2015-02-20 18:41:35
【问题描述】:

我是 django 新手,所以请耐心等待 :)

像以前的许多人一样,我正在尝试构建一个 reddit 克隆。我已经完成了所有工作,但缺少一部分。在不产生太多数据库请求的情况下,我想指出当前用户是否为特定问题投票。

这是我的模型的样子:

from django.db import models
from django.conf import settings
from mptt.models import MPTTModel, TreeForeignKey

max_post_length = 2000


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 %}

填充 node.up_vote_by_user 和 node.down_vote_by_user 的最佳方式是什么? 我尝试使用用户中间件和模型方法。我也尝试过对 cme​​ts 进行预迭代,但这不能与用于列表的递归一起使用。

【问题讨论】:

    标签: python django django-models django-views


    【解决方案1】:

    首先,看起来CommentThread 的超集,换句话说,它们都使用相同的字段,如titletextusercreated 等,所以如果我站在你的立场上,我会创建一个名为 Nodeabstract base class 并将这些字段放入基本模型中:

    class Node(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)
        up_votes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='%(class)s_upvotes')
        down_votes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='%(class)s_downvotes')
    
        class Meta:
            abstract = True
    
        def __str__(self):
            return self.title
    
    class Thread(Node):
        pass
    
    class Comment(Node, MPTTModel):
        thread = models.ForeignKey(Thread)
        parent = TreeForeignKey('self', related_name='children', blank=True, null=True)
        vote_count = models.IntegerField(default=0)
    
        class MPTTMeta(Node.Meta):
            order_insertion_by = ['created']
    

    对于您关于如何查找用户是否对特定问题进行投票的实际问题,假设您不想用现有模型替换您自己的 User 模型,我肯定会迭代用户:(我不知道为什么它不适合你)

    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()
    

    通过这种方式,您甚至不仅可以搜索 cmets,还可以搜索特定用户投票的主题。但是,为了在模板中使用这些方法,您必须编写自己的 template filter,将 request.user 作为参数。

    @register.filter
    def up_voted_by(obj, user):
        return obj.upvoted_by(user)
    

    我认为您不会对上述解决方案的性能感到满意,因为它会针对每个节点实例访问数据库,因此如果线程有这么多 cmets,您最终可能会导致网页加载时间过长。因此,更好的选择是迭代用户的投票并过滤与线程匹配的投票。

    (我认为还有另一种解决方案可以更快、更高效地获取 here 中评论对象的所有后代,但我发现它很难理解。

    def get_all_descendants(nodes, include_self=True):
         result = set()
         for node in nodes:
            descendants = node.get_descendants(include_self=include_self)
            result.update(set(descendats.values_list('pk', flat=True)))
         return result
    
    def detail(request, thread_id):
        thread = get_object_or_404(Thread, pk=thread_id)
    
        comments = thread.comment_set.all()
        descendants = get_all_descendants(comments, include_self=True)
    
        upvoted_comments = request.user.comment_upvotes.filter(
            id__in=descendants).values_list('pk', flat=True)
    
        downvoted_comments = request.user.comment_downvotes.filter(
            id__in=descendants).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)
        })
    

    然后,您可以在模板中轻松检查0(1) 中的评论是否被赞成或反对:

    {% 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 %}"
    
      ...
    

    【讨论】:

    • 非常感谢。这已经很有帮助了。我对这个感到沮丧。 upvoted_comments = request.user.comment_upvotes.filter( comment__in=descendants).values_list('pk', flat=True)downvoted_comments = request.user.comment_downvotes.filter(comment__in=comment_ids).exclude(id__in=upvoted_comments).values_list('pk', flat=True) 似乎不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 2013-01-06
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多