web-dev-qa-db-ja.com

Django-スレッド化されたコメントを実装する適切な方法

Djangoを使用してブログサイトを開発しています。私のサイトでは、ユーザーが私のブログ投稿にコメントしたり、お互いに返信したりできるようになり、「スレッドコメント」構造を使用して表示されます(ユーザー機能はまだ開始していません。コメントのみです)。 Django-mpttを使用してスレッド化されたコメントが正しく機能するようになっていますが(少なくとも今のところ)、実行しているルートまたは手順が正しい方向にあるかどうかはわかりません。私が経験したほとんどすべてのチュートリアルは、コメントに関しては表面的なものにすぎず、Djangoのスレッド化されたコメントについては説明していません。何が間違っているのか、何がもっとうまくできるのかについて、経験豊富な専門家のアドバイスが必要です。私が最後に望んでいるのは、何時間もの作業を行った後、はるかに受け入れられる方法があったことを見つけることです。

だから、これが私が明確にする必要があるもののリストです:

  1. Django-mptt:

    • 書き込み時間を遅くする余裕があるので、これを選択しました。私のサイトは書き込みよりも読み取りが多くなります。このオプションは私の場合は大丈夫ですか?私が知らないより良い代替案はありますか?
    • 私のサイトにたくさんのコメント活動があった場合はどうすればよいですか?ツリーの再構築を最適化するにはどうすればよいですか?それとも、隣接リストに切り替えたほうがいいでしょうか?
    • 私のMPTTコメントモデルには、それ自体を参照するForeignKeyがあります(応答用)。これは正しい方法ですか?または、別の返信モデルを作成する必要がありますか?
    • ツリーに別のユーザーのコメントへの返信を挿入する方法は、mptt再帰テンプレートタグ内にあるフォーム内の非表示の入力を使用し、入力値(返信の対象となるコメントのID)を返し、設定することです。その入力値への応答の親。これは受け入れられている方法ですか?
  2. 1つのHTMLページに複数のフォーム

    • ブログ投稿のHTMLページに2つのフォームがあります。 1つはブログ投稿にコメントするためのもので、もう1つはユーザーのコメントに返信するためのものです。これは受け入れられますか?または、異なる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]

なんらかの奇妙な理由で「そのような列がありません:承認されました」というエラーが表示されるため、「承認済み」はコメントアウトされています。

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'),
    ]
18

MPTTツリーは、サブノードまたはノード数のリストを取得するのに最適です。これらはノードの追加/挿入にコストがかかり、コストは3つのサイズに比例して増加します。これらは、ツリーデータをリレーショナルデータベースに適合させるように設計されています。また、「書き込みよりも読み取りの方がはるかに多い」と騙されないでください。理想的には、ほとんどの読み取りは、その下のデータベースではなく、キャッシュにヒットする必要があります。

リレーショナルデータベースをスキップして、ツリーをネイティブに格納できるNoSQLデータベースを使用してみませんか? Djangoと、ほぼすべてのNoSQLデータベースを簡単に統合できます。

1
rbanffy