【问题标题】:How to create nested comment system with django-mptt如何使用 django-mptt 创建嵌套评论系统
【发布时间】:2017-01-21 14:30:23
【问题描述】:

我正在写一个简单的博客,我正在尝试为每个帖子实现一个嵌套评论系统。

我为 cmets 创建了模型,它通过 Django 管理页面运行良好。

我不知道如何创建用于发布新评论和回复的表单。

这是我目前所拥有的:

models.py

(...)
class Post(models.Model):
    author = models.ForeignKey('Author', on_delete=models.CASCADE)
    title = models.CharField(max_length=250)
    slug = models.SlugField(unique=True, blank=True, max_length=250)
    created = models.DateTimeField(auto_now=False, auto_now_add=True)
    modified = models.DateTimeField(auto_now=True, auto_now_add=False)
    tags = TaggableManager(blank=True)
    image = models.ImageField(upload_to="images/%Y/%m/", blank=True, null=True)
    content = models.TextField()

    def get_absolute_url(self):
        return reverse('post_detail', kwargs={'slug': self.slug, })

    # create slug
    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = slugify(unidecode(self.title))
        super(Post, self).save(*args, **kwargs)

    def __str__(self):
        return str(self.title)

class Comment(MPTTModel):
    post = models.ForeignKey("Post", on_delete=models.CASCADE, null=True, related_name='comments')
    parent = TreeForeignKey('self', null=True, blank=True, related_name='replies', db_index=True)

    name = models.CharField(max_length=250)
    email = models.EmailField(max_length=250, blank=True, null=True)
    website = models.CharField(max_length=250, blank=True, null=True)
    created = models.DateTimeField(auto_now=False, auto_now_add=True)
    content = models.TextField()

    def __str__(self):
        return str("{}: {}...".format(self.name, self.content[:50]))

forms.py

class CommentForm(forms.ModelForm):

    class Meta:
        model = Comment
        fields = [ "name", 'email', 'website', 'content']

views.py

class PostDetailView(DetailView):
    model = Post

    def get_context_data(self, **kwargs):
        context = super(PostDetailView, self).get_context_data(**kwargs)
        context['form'] = CommentForm()
        return context


class PostCommentView(SingleObjectMixin, FormView):
    template_name = 'blog/post_detail.html'
    form_class = CommentForm
    model = Post

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(PostCommentView, self).post(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('post_detail', kwargs={'slug': self.object.slug})

class PostDetail(View):

    def get(self, request, *args, **kwargs):
        view = PostDetailView.as_view()
        return view(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        view = PostCommentView.as_view()
        return view(request, *args, **kwargs)

comment_form.html

<div id="respond">
    <h2 class="respond-title">Leave a comment</h2>
    <span class="form-caution">Make sure you enter the (*) required information where indicated. HTML code is not allowed.</span>
    <form action="" method="post">
        {{ form.non_field_errors }}
        {% csrf_token %}
        {{  form }}
         <input name="submit" type="submit" id="submit" class="btn btn-primary" value="Submit Comment">
    </form>
</div>

【问题讨论】:

标签: python django django-models django-mptt


【解决方案1】:

一般

修改前序树遍历并不是构建嵌套 cmets 的最佳解决方案。考虑到每个新节点都必须重建整个树。例如,让我们想象一下帖子 F 下的 cmets:

//             F
//           / | \
//          B  X  G
//         / \
//        Z   Y

请注意,注释 X 的左侧值为 8,右侧值为 9。但是,对于 B 或 X 的每个新子注释,这些值都会发生变化。例如。在注释下添加新注释时,X 的 Z 值将更改为 lft = 10 和 rht = 11。这可能会导致糟糕的性能,而且,正如我想象的那样,在信使的情况下数据丢失意味着信息仅发送一次(例如 Django频道)。


定制现成的解决方案

This post 提出了通过连接内置评论应用程序和 mptt 实现嵌套推荐系统的解决方案。这是一个旧帖子,自 Django 1.6 以来,django.contrib.comments 已被分离为 separate project。最近 Tim Graham 添加了支持 Django 2.0 的更改,因此它看起来是最新的。

这个想法是创建一个自定义模型和表单,它将添加到 Django_cmets 的标题字段中。该帖子建议这样接线:

Models.py

from django_comments.models import Comment
from mptt.models import MPTTModel, TreeForeignKey

class MPTTComment(MPTTModel, Comment):
    """ Threaded comments - Add support for the parent comment store and MPTT traversal"""

    # a link to comment that is being replied, if one exists
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children')

    class MPTTMeta:
        # comments on one level will be ordered by date of creation
        order_insertion_by=['submit_date']

    class Meta:
        ordering=['tree_id','lft']

Forms.py

from django import forms
from django.forms.widgets import widgets        
from django_comments.forms import CommentForm                            
from models import MPTTComment

class MPTTCommentForm(CommentForm):
    parent = forms.ModelChoiceField(queryset=MPTTComment.objects.all(),
        required=False, widget=forms.HiddenInput)

    def get_comment_model(self):
        # Use our custom comment model instead of the built-in one.
        return MPTTComment

    def get_comment_create_data(self):
        # Use the data of the superclass, and add in the parent field field
        data = super(MPTTCommentForm, self).get_comment_create_data()
        data['parent'] = self.cleaned_data['parent']
        return data

__init__.py 在您的应用目录中

from models import MPTTComment
from forms import MPTTCommentForm

def get_model():
    return MPTTComment

def get_form():
    return MPTTCommentForm

还有另一个 django 包,这个已经内置了嵌套 cmets:django-threadedcomments。值得一试。

【讨论】:

  • 您能否在答案中引用链接帖子中的任何相关摘录?按原样,您的答案不适合 Stack Overflow - 它极易受到链接腐烂的影响。
猜你喜欢
  • 1970-01-01
  • 2019-02-23
  • 2011-07-13
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 2013-03-10
  • 1970-01-01
  • 2018-05-24
相关资源
最近更新 更多