如何使用 django-mptt 创建嵌套评论系统
How to create nested comment system with django-mptt
我正在开发简单的博客,我正在尝试为每个 post.
实现一个嵌套的评论系统
我为评论创建了模型,它通过 Django 管理页面运行良好。
我不知道如何创建用于post新评论和回复的表单。
这是我目前的情况:
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>
一般
改进的预序树遍历不是构建嵌套评论的最佳解决方案。考虑到每个新节点都必须重建整棵树。例如,假设 post F:
下的评论
// F
// / | \
// B X G
// / \
// Z Y
请注意,注释 X 的左值为 8,右值为 9。但是,对于 B 或 X 的每个新子注释,这些值都会发生变化。例如。在评论下的新评论中,X 的 Z 值将更改为 lft = 10 和 rht = 11。这可能会导致糟糕的性能,并且正如我想象的那样,在信使的情况下数据丢失意味着信息只发送一次(例如 Django频道)。
定制现成的解决方案
This post presents solution for achieving nested commend system by connecting inbuilt comment app and the mptt. It's an old post and the django.contrib.comments
has been separated to a separate project 从 Django 1.6 开始。最近 Tim Graham 添加了支持 Django 2.0 的更改,所以看起来 up-to-date.
我们的想法是创建一个自定义模型和表单,将添加到 Django_comments 的标题字段。 post 建议这样接线:
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 包,这个已经带有嵌套注释 built-in:django-threadedcomments。值得一看。
我正在开发简单的博客,我正在尝试为每个 post.
实现一个嵌套的评论系统我为评论创建了模型,它通过 Django 管理页面运行良好。
我不知道如何创建用于post新评论和回复的表单。
这是我目前的情况:
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>
一般
改进的预序树遍历不是构建嵌套评论的最佳解决方案。考虑到每个新节点都必须重建整棵树。例如,假设 post F:
下的评论// F
// / | \
// B X G
// / \
// Z Y
请注意,注释 X 的左值为 8,右值为 9。但是,对于 B 或 X 的每个新子注释,这些值都会发生变化。例如。在评论下的新评论中,X 的 Z 值将更改为 lft = 10 和 rht = 11。这可能会导致糟糕的性能,并且正如我想象的那样,在信使的情况下数据丢失意味着信息只发送一次(例如 Django频道)。
定制现成的解决方案
This post presents solution for achieving nested commend system by connecting inbuilt comment app and the mptt. It's an old post and the django.contrib.comments
has been separated to a separate project 从 Django 1.6 开始。最近 Tim Graham 添加了支持 Django 2.0 的更改,所以看起来 up-to-date.
我们的想法是创建一个自定义模型和表单,将添加到 Django_comments 的标题字段。 post 建议这样接线:
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 包,这个已经带有嵌套注释 built-in:django-threadedcomments。值得一看。