Xử lý bình luận bài viết trong Python Django

Lập trình web với Python bằng Django

0.0 (0 đánh giá)
Tạo bởi Kteam Cập nhật lần cuối 14:48 02-12-2019 14.889 lượt xem 8 bình luận
Học nhanh

Danh sách bài học

Xử lý bình luận bài viết trong Python Django

Ghi chú

Nội dung bài viết bạn đang xem được update từ tháng 06/2019. Vì vậy sẽ có đôi chút khác biệt giữa VIDEO và NỘI DUNG BÀI VIẾT.

Chúng ta sẽ có nhiều cập nhập hơn về cả bài viết lẫn video trong thời gian tới. Nhớ like / share hoặc đánh giá 5 sao để Kteam có động lực nhé! 

Cảm ơn các bạn! 


Dẫn nhập

Ở bài trước, Kteam đã hướng dẫn các bạn xong SỬ DỤNG GENERIC VIEW TRONG PYTHON

Trong bài này Kteam sẽ hướng dẫn cho các bạn cách tạo các bình luận trong bài viết của blog.


Nội dung

Để theo dõi bài này tốt nhất, bạn nên xem qua bài:

Bài này sẽ giới thiệu những nội dung sau:

  • Thiết kế bảng Comment
  • Tạo Form Comment
  • Xử lý code bình luận
  • Thiết kế lại template
  • Hiển thị bình luận trong django admin

Thiết kế bảng Comment

Trước tiên ta sẽ thiết kế bảng Comment, ta sẽ thiết kế ở models.pyapp blog:

from django.conf import settings

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    body = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
  • ở đây Kteam sử dụng field ForeignKey để cho Django xác định đây là khóa ngoại, việc dùng ForeignKey để áp dụng trường hợp mối quan hệ 1-nhiều. Vì trường hợp blog này là 1 bài viết có nhiều bình luận nhưng 1 bình luận chỉ dành cho 1 bài viết (tương tự với user và bình luận).
  • ta khai báo field post là khóa ngoại liên kết với bảng Post, tham số on_delete Kteam cho nó thuộc loại CASCADE (có nghĩa là khi xóa bài viết thì xóa luôn bình luận), tham số related_name có nghĩa khi dev muốn tìm các bình luận từ một bài viết thì thông qua từ khóa ‘comments’ từ post.
  • tương tự author là khóa ngoại liên kết bảng user của hệ thống Django để biết ai là người bình luận bài viết.
  • body lưu nội dung bình luận, date lưu ngày viết bình luận.

Tạo Form Comment

Tiếp theo, Kteam sẽ thiết kế form comment để hiển thị cho template. Bây giờ Kteam sẽ sử dụng ModelForm để giúp ta tạo các field input form. Ở app blog, ta tạo thêm 1 file forms.py để xử lý:

from django import forms
from .models import Comment

class CommentForm(forms.ModelForm):
    
    def __init__(self, *args, **kwargs):
        self.author = kwargs.pop('author', None)
        self.post = kwargs.pop('post', None)
        super().__init__(*args, **kwargs)

    def save(self, commit=True):
        comment = super().save(commit=False)
        comment.author = self.author
        comment.post = self.post
        comment.save()

    class Meta:
        model = Comment
        fields = ["body"]
  • khai báo CommentForm kế thừa forms.ModelForm.
  • trong class có thêm class Meta để xử lý thông tin model: ta cho form này xử lý model Comment, vì ở bảng này ta chỉ nhập nội dung của bình luận (tên tác giả và bài viết được comment không thể nhập tay được) nên khai báo fields chỉ có body để form chỉ tạo input body.
  • Kteam override phương thức khởi tạo, mục đích là lấy giá trị author post để lưu vào bảng comment. Sau khi lấy xong thì ta gọi tiếp phương thức khởi tạo của class cha.
  • Kteam override phương thức save có sẵn của ModelForm, việc override này mục đích gán giá trị author post. Đầu tiên là gọi phương thức save của class cha (ta cho tham số commit = False để chưa lưu xuống database). Sau đó lấy instance comment ra và gán giá trị author và post rồi mới gọi phương thức save() của model.

Xử lý code bình luận

views.py trong app blog, ta sẽ xử lý hiển thị form bình luận cho bài viết và xử lý khi người dùng bình luận:

from django.shortcuts import render, get_object_or_404
from .models import Post, Comment
from .forms import CommentForm
from django.http import HttpResponseRedirect
# Create your views here.

def post(request, pk):
    post = get_object_or_404(Post, pk=pk)
    form = CommentForm()
    if request.method == "POST":
        form = CommentForm(request.POST, author=request.user, post=post)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(request.path)
    return render(request, "blog/post.html", {"post": post, "form": form})
  • dùng get_object_or_404 để tìm bài viết qua khóa chính, nên không thấy thì trả về 404.
  • nếu không phải method POST thì khởi tạo form bình thường để hiển thị cho người dùng viết bình luận.
  • nếu method bằng POST thì ta xử lý data từ máy user gửi về, ta khởi tạo lại CommentForm với truyền dữ liệu POST vào, ngoài ra thêm dữ liệu user đang đăng nhập và bài viết được bình luận. Nếu form hợp lệ thì lưu bài viết, sau đó redirect lại đường dẫn để mất đi thông tin POST (vì nếu không redirect thì khi user nhấn F5 thì lại gửi lại thông tin bình luận).
  • xử lý render truyền bài viết và form vào.

Bây giờ, ta chỉnh lại path để khi vào đường dẫn bài viết sẽ gọi hàm xử lý này:

from django.urls import path
from .models import Post
from . import views
from django.views.generic import ListView

urlpatterns = [
   path('', ListView.as_view(
      queryset = Post.objects.all().order_by('-date'),
      template_name = 'blog/blog.html',
      context_object_name = 'Posts',
      paginate_by = 1)
      , name='blog'),
   path('<int:pk>/', views.post, name='post'),
]

PostDetailView thì class sẽ truy vấn bằng primary key, nên thay url id thành pk để path hợp lệ.vì là class nên không thể đưa class thẳng vào url, ta sẽ gọi function as_view của class.

Thiết kế lại template

Bây giờ, ở template post.html ta phải thiết kế lại để hiển thị bình luận và form cho user bình luận:

{% extends "pages/base.html" %}
 
{% block title %}{{post.title}}{% endblock %}
 
{% block content %}
<h3><a href="/redirect?Id=duECimTrtcY%2f9%2fkQF45R8ricuL8rnN1W89bqLQLRmAR%2b2AE1Wuc2%2fsatIaeyTQ2SiSNKPWJ7vem62cw9ZxE2LzZQEtuy6DuaTgL6aoimSYA%3d"
<img src="{{post.image.url}}" width="500px" height="300px" />
<h6>on {{post.date}}</h6>
{{post.body|safe|linebreaks}}

{% for comment in post.comments.all %}
    <h4><strong>{{comment.author}}</strong></h4>
    <h6><p>{{comment.date}}</p></h6>
    <p>{{comment.body|linebreaks}}</p>
{% endfor %}
{% if user.username %}
    <form action="{% url 'post' post.id %}" method="POST">
        {% csrf_token %}
        <p><label>Bình luận:</label></p>
        {{form.body}}
        <br/>
        <input type="submit" value="Bình luận"/>
    </form>
{% endif %}
{% endblock %}
  • dùng post.comments.all để lấy hết bình luận trong bài viết đó, ‘comments’ chính là related_name ta đã khai báo ở models.
  • dùng vòng lặp for để hiển thị hết thông tin.
  • form, ta kiểm tra user có đăng nhập chưa, nếu đăng nhập mới hiển thị form bình luận.

Bây giờ, ta sẽ kiểm tra kết quả:


Hiển thị bình luận trong django admin

Bây giờ, Kteam muốn admin hiển thị bình luận ngay ở trong thông tin bài viết để dễ quản lý hơn, ta có thể sử dụng StackedInline của django admin như sau:              

from django.contrib import admin

# Register your models here.
from .models import Post, Comment

# Register your models here.
class CommentInline(admin.StackedInline):
    model = Comment

class PostAdmin(admin.ModelAdmin):
    list_display = ['title', 'date']
    list_filter = ['date']
    search_fields = ['title']
    inlines = [CommentInline]
 
admin.site.register(Post, PostAdmin)

Hoặc ta sử dụng TabularInline:

from django.contrib import admin

# Register your models here.
from .models import Post, Comment

# Register your models here.
class CommentInline(admin.TabularInline):
    model = Comment

class PostAdmin(admin.ModelAdmin):
    list_display = ['title', 'date']
    list_filter = ['date']
    search_fields = ['title']
    inlines = [CommentInline]
 
admin.site.register(Post, PostAdmin)


Project tham khảo

Nếu quá trình thực hành của bạn không diễn ra suôn sẻ như bài hướng dẫn thực hiện, bạn có thể tham khảo Project mẫu của Kteam trong link bên dưới hoặc để lại BÌNH LUẬN để được hỗ trợ nhé!

Đừng quên like hoặc +1 Google để ủng hộ Kteam và tác giả nhé! 


Kết luận

Trong bài này, chúng ta đã tìm hiểu cách Tạo bình luận trong bài viết và kết thúc khóa LẬP TRÌNH WEBSITE VỚI PYTHON BẰNG DJANGO

Cảm ơn các bạn đã theo dõi bài viết. Hãy để lại bình luận hoặc góp ý của mình để phát triển bài viết tốt hơn. Và đừng quên “Luyện tập – Thử Thách – Không ngại khó


Thảo luận

Nếu bạn có bất kỳ khó khăn hay thắc mắc gì về khóa học, đừng ngần ngại đặt câu hỏi trong phần BÌNH LUẬN bên dưới hoặc trong mục HỎI & ĐÁP trên thư viện Howkteam.com để nhận được sự hỗ trợ từ cộng đồng.

Nội dung bài viết

Tác giả/Dịch giả

Khóa học

Lập trình web với Python bằng Django

Lập trình web với Python bằng Django

Đánh giá

Bình luận

Để bình luận, bạn cần đăng nhập bằng tài khoản Howkteam.

Đăng nhập
trthphong29 đã bình luận 14:58 06-01-2019

Tôi rất mừng khi gặp loạt bài hướng dẫn Djago này cúa KTeam, vì hiện tại các tài liệu tiếng Việt đầy đủ về chủ đề này quá ít. Tôi học được khá nhiều từ nó. Xin góp ý thêm: trong ví dụ mẫu này có qua nhiều từ 'post'. Khi học tôi rất khó nhận diện được đâu là gọi trỏ tới, đâu là biến, đâu là table, đâu là tên field. Các bài sau này mong bạn hạn chế việc "giống từ ngữ" để người học dễ nhận diện hơn. Ví dụ: table thì là tpost, cột thì là cpost, biến thì vpost,  gán tên thì là npost, v v . . . Hiện tại tôi đã đổi được TenBang và TenField và nhiều tên khác. Nhưng chưa đổi được trong blog/urls.py dòng

path('<int:pk>/', views.pst , name='post') : chạy tốt khi đổi các liên quan của view.post thành view.pst

thành path('<int:pk>/', views.pst , name='npost'): không tìm ra hết các lỗi (tất nhiên là do tôi chưa hiểu sâu).

Rất e ngại khi nhờ bạn chỉ chỗ sửa liên quan này. Cảm ơn bạn.

trthphong29 đã bình luận 15:08 23-02-2018

Tôi muốn view hoặc render 1 file html (ví dụ: thongke.html - vẫn thuộc project PythonWeb) nằm ngoài folder templates thì xác lập cách nào ? Xem video của bạn, tôi đã thử tạo thêm nhiều app trong pythonWeb, tạo thêm nhiều file html và trỏ đến nó từ views.py hoặc urls.py đều được nếu file html nằm trong folder template, nhưng tôi không load được nếu file html nằm ngoài Folder template. Mong được bạn hướng dẫn. Rất cảm ơn.

Lê Châu Moderator đã bình luận 22:52 16-02-2018

source code cho ai cần: Link

dmatttqd đã bình luận 21:20 18-11-2017

Cảm ơn mọi người.Các bạn có thể làm thêm video về deploy lên sever ko.Nó khá khó hiểu với những người mới như mình

evilcatkimi đã bình luận 15:09 09-10-2017

Bạn ơi up source code project lên giúp mình nhé :)

Không có video.