Django - 实现线程注释的正确方法

Bry*_*ffe 18 python django threaded-comments django-mptt

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

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

  1. Django的MPTT:

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

    • 我的博客文章html页面上有两个表单.一个评论博客文章,一个回复用户的评论.这被接受了吗?或者我应该为不同的表单创建不同的URL和查看功能?我是这样做的,因为我想要一个reddit风格的评论系统.我不希望它必须去另一个页面评论或回复.
    • 如果用户对我的博客帖子发表评论,则回复表单中的隐藏输入值不会返回任何内容,因此在尝试将其分配给views.py函数中的变量时会出现错误.我使用try/except块来修复它.这有更好的方法吗?

对不起,如果这些是菜鸟问题,我的帖子就这么久了.我只想用最好的方法为初学者使用现实的解决方案.任何反馈都会有帮助.谢谢!这是我的博客应用程序的代码.

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]
Run Code Online (Sandbox Code Playgroud)

"已批准"已被注释掉,因为出于某种奇怪的原因我得到了"没有这样的列:已批准"错误.

forms.py

    from django import forms

    from .models import Post, Comment

    class CommentForm(forms.ModelForm):
        class Meta:
            model = Comment
            fields = ['user_comment']
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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 %}
Run Code Online (Sandbox Code Playgroud)

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'),
    ]
Run Code Online (Sandbox Code Playgroud)

rba*_*ffy 3

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

为什么不跳过关系数据库并使用可以本地存储树的 NoSQL 数据库呢?Django 和几乎所有您能想到的 NoSQL 数据库都可以轻松集成。