Django - 实现线程评论的正确方法

时间:2018-02-08 03:52:48

标签: python django django-mptt threaded-comments

我正在使用Django开发博客网站。我的网站将允许用户对我的任何博客帖子发表评论,并相互回复,并将使用“线程评论”进行显示。结构(我还没有启动用户功能,只是评论)。我已经使用django-mptt(至少现在)正确地使用了线程注释,但是如果我采取的路线或步骤正确,我没有CLUE。我所经历过的几乎所有教程都只涉及到评论的表面,并且没有谈论django中的线程评论。我想要一些经验丰富/专业的建议,告诉我可能做错了什么,以及我可以做得更好。我想要的最后一件事就是在经过数小时的工作后发现有一种更可接受的方式。

所以,这里列出了我需要明确的内容:

  1. 的django-MPTT:

    • 我选择了这个,因为我可以负担得起更慢的写入时间。我的网站将有更多的读取而不是写入。这个选项对我的情况好吗?有没有更好的选择我不知道?
    • 如果我的网站最终有很多评论活动,我该怎么办?我该怎么做才能优化树木重组?或者我会更好地切换到邻接列表?
    • 我的MPTT评论模型有一个以自己为引用的ForeignKey(用于回复)。这是正确的方法吗?或者我应该创建一个单独的回复模型吗?
    • 我在树中插入对其他用户评论的回复的方式是使用mptt递归模板标签内的表单中的隐藏输入,并返回输入值(即id回复所针对的评论)并将回复的父级设置为该输入值。这是一种公认​​的方法吗?
  2. 一个html页面上的多个表单

    • 我的博客文章html页面上有两个表单。一个评论博客文章,一个回复用户的评论。这被接受了吗?或者我应该为不同的表单创建不同的URL和查看功能?我是这样做的,因为我想要一个reddit风格的评论系统。我不希望它必须转到其他页面进行评论或回复。
    • 如果用户对我的博客帖子发表评论,则回复表单中的隐藏输入值不会返回任何内容,因此在尝试将其分配给views.py函数中的变量时会出错。我使用try / except块来修复它。有更好的解决方法吗?
  3. 对不起,如果这些是菜鸟问题而且我的帖子太久了。我只想用最好的方法为初学者使用现实的解决方案。任何反馈都会有帮助。谢谢!这是我的博客应用程序的代码。

    models.py

        from django.db import models
    
        from mptt.models import MPTTModel, TreeForeignKey
    
        class Post(models.Model):
            """Blog post"""
            title = models.CharField(max_length=200)
            body = models.TextField()
           date_added = models.DateTimeField(auto_now_add=True)
    
            def __str__(self):
                return self.body[:50] + '...'
    
        class Comment(MPTTModel):
            """User comment"""
            post = models.ForeignKey(Post, related_name='comments',on_delete=models.CASCADE)
            parent = TreeForeignKey('self', null=True, blank=True, related_name='children',db_index=True, on_delete=models.CASCADE)
    
            user_comment = models.CharField(max_length=500, unique=True)
            date_added = models.DateTimeField(auto_now_add=True)
            # approved = models.BooleanField(default=False)
    
            class MPTTMeta:
                order_insertion_by = ['date_added']
    
            def __str__(self):
                return self.user_comment[:20]
    

    '批准'被评论出来是因为我没有这样的专栏:批准'因某些奇怪的原因而出错。

    forms.py

        from django import forms
    
        from .models import Post, Comment
    
        class CommentForm(forms.ModelForm):
            class Meta:
                model = Comment
                fields = ['user_comment']
    

    views.py

        from django.shortcuts import render
        from django.http import HttpResponseRedirect
        from django.urls import reverse
    
        from .models import Post
        from .forms import CommentForm
    
        def posts(request):
            """Show all blog posts"""
    
            posts = Post.objects.order_by('-date_added')
    
            context = {
                'posts': posts
            }
            return render(request, 'posts/posts.html', context)
    
        def post(request, post_id):
            """Show single blog post"""
    
            post = Post.objects.get(id=post_id)
            comments = post.comments.all()
    
            if request.method != 'POST':
                comment_form = CommentForm()
    
            else:
                comment_form = CommentForm(data=request.POST)
                try:
                    parent_id = request.POST['comment_id']
                except:
                    pass
                if comment_form.is_valid():
                    comment = comment_form.save(commit=False)
                    comment.post = post
                    comment.parent = comments.get(id=parent_id)
                    comment.save()
                    return HttpResponseRedirect(reverse('posts:post', args=[post_id]))
    
            context = {
                'post': post,
                'comment_form': comment_form,
                'comments': comments,
            }
            return render(request, 'posts/post.html', context)
    

    post.html

        {% extends 'posts/base.html' %}
    
        {% block blog_content %}
    
            <h1>Post page!</h1>
    
            <h3>{{ post.title }}</h3>
            <h4>{{ post.date_added }}</h4>
            <p>{{ post.body }}</p>
    
            <form method="post" action="{% url 'posts:post' post.id %}">
              {% csrf_token %}
              {{ comment_form.as_p }}
              <button type="submit">Add comment</button>
            </form>
    
            {% load mptt_tags %}
              {% recursetree comments %}
              <h5>{{ node.date_added }}</h5>
              <p>{{ node.user_comment }}</p>
                  <form method="post" action="{% url 'posts:post' post.id %}">
                  {% csrf_token %}
                  {{ comment_form.as_p }}
                  <input type="hidden" name="comment_id" value="{{ node.id }}">
                  <button type="submit">Reply</button>
                  </form>
              {% if not node.is_leaf_node %}
                <div style="padding-left: 20px">
                {{ children }}
                </div>
              {% endif %}
              {% endrecursetree %}
    
    
        {% endblock %}
    

    urls.py

        from django.urls import path
    
        from . import views
    
        app_name = 'posts'
        urlpatterns = [
            path('posts/', views.posts, name='posts'),
            path('posts/<int:post_id>/', views.post, name='post'),
        ]
    

1 个答案:

答案 0 :(得分:1)

MPTT树非常适合获取子节点列表或节点数。它们增加/插入节点的成本很高,并且成本随着三个节点的大小线性增加。它们旨在使树数据适合关系数据库。另外,不要被“我的读写要多得多”所迷惑。理想情况下,大多数读取应命中缓存,而不是缓存下的数据库。

为什么不跳过关系数据库,而选择可以原生存储树的NoSQL数据库呢? Django和几乎每个NoSQL数据库都可以轻松集成。