Hiển thị thông tin bài viết trong Python Django

Nội dung

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

  • Tạo url để hiển thị bài viết thông qua id
  • Xử lý lấy thông tin bài viết
  • Viết testcase

Tạo url để hiển thị bài viết thông qua id

Ở bài học trước, Kteam đã tạo đường dẫn url như sau:

<h4>{{post.date|date:"d-m-Y"}}<a href="/redirect?Id=LjOsTEjdap3loco%2bU474Qv%2bkTfyY1VKeVYzd0Ut4dMs%3d">{{post.title}}</a></h4>

Khi render thì sẽ tạo đường link như thế này:

Như vậy, mục đích của Kteam là tạo đường dẫn /blog/id để dựa vào id mà hiện thị đúng chi tiết bài viết. Ở file urls.py của app blog cần khai báo path đó như sau:

urlpatterns = [
   path('', views.list),
   path('<int:id>/', views.post),
]

Vì id của bài viết là linh động, mình phải khai báo theo cú pháp <kiểu dữ liệu:keyword>. Tiếp theo, Kteam sẽ viết hàm post ở views để xử lý thông tin bài viết.


Xử lý lấy thông tin bài viết

Bây giờ, ta sẽ viết hàm post để xử lý path trên:

def post(request, id):
    post = Post.objects.get(id=id)
    return render(request, 'blog/post.html', {'post': post})

Ở hàm post, ngoài tham số request, ta còn thêm tham số id tương ứng keyword id ở path. Sau đó, ta sẽ truy vấn bài viết bằng id trên. Rồi đưa bài viết vào render, bây giờ kteam sẽ thiết kế template post.html.

{% extends "pages/base.html" %}
 
{% block title %}{{post.title}}{% endblock %}
 
{% block content %}
<h3><a href="/redirect?Id=AowXW6GamzKEfhgo%2f2TLKjERqDpbWoXjWVP4OrGyoBU%3d">{{post.title}}</a></h3>
<h6>on {{post.date}}</h6>
{{post.body|safe|linebreaks}}
{% endblock %}
  • Ở block title ta sẽ thấy tiêu đề của bài viết đưa vào.
  • Hiển thị rõ tiêu đề bài viết lớn trong tag <h3>.
  • Hiển thị ngày viết bài trong tag <h6>.
  • Hiển thị nội dung bài viết, ta thêm safe để có thể render nếu trong body có thẻ html và linebreaks để chuyển các ký tự enter (\n) sang tag <br/>.

Bây giờ ta kiểm tra kết quả, vào phần các bài viết và click tiêu đề:

Như vậy ở url /blog/1 đã hiển thị ra bài viết có id bằng 1. Giờ ta thử quay về Admin chỉnh sửa lại bài viết này

Nếu ta cho tag <h1> thì safe sẽ render đúng chức năng của html của nó

Giờ ta thử xóa safe sẽ ra kết quả nguyên bản

Nếu ta thử xuống dòng ở phần body như sau

Vì ở máy tính thì xuống dòng là kí hiệu \n, nhưng ở html không hiểu kí hiệu này nên linebreaks có chức năng chuyển sang thẻ <br/> để đúng cách chia bố cục của bài viết.


Viết testcase

Bây giờ, Kteam sẽ viết 1 số test case để kiểm tra code mình đã viết vừa rồi, ta sẽ mở file tests.py để xử lý:

from django.test import TestCase
from .models import Post
# Create your tests here.
class BlogTests(TestCase):
    def setUp(self):
        Post.objects.create(
            title='myTitle',
            body='just a Test'
        )

    def test_string_representation(self):
        post = Post(title='My entry title')
        self.assertEqual(str(post), post.title)

    def test_post_list_view(self):
        response = self.client.get('/blog/')
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'myTitle')
        self.assertTemplateUsed(response, 'blog/blog.html')

    def test_post_detail_view(self):
        response = self.client.get('/blog/1/')
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'myTitle')
        self.assertTemplateUsed(response, 'blog/post.html')
  • Phương thức setUp đầu tiên là tạo 1 bài viết trong hệ thống test, bài viết được tạo ở đây sẽ không ảnh hưởng gì đến database đang làm.
  • Phương thức test_string_representation nhằm để kiểm tra phương thức __str__ của Post có ra giá trị title không. Kteam tạo ra 1 post và so sánh hai giá trị dùng hàm gán str() và gọi tiêu đề title ra.
  • Phương thức test_post_list_view kiểm tra chức năng hiển thị danh sách bài viết, bằng cách vào đường dẫn /blog/ kiểm tra status code có trả về 200 không? Trong response có tiêu đề bài viết không? Có sử dụng template blog.html như đã làm không.
  • Phương thức test_post_detail_view kiểm tra chức năng hiển thị thông tin bài viết, cách kiểm tra cũng tương tự hiển thị danh sách bài viết.

Leave a Reply