Khởi đầu với Django: Những lưu ý cần biết
Yo anh em! Một trong những sở thích cực kỳ "tao nhã" của mình gần đây là mò mẫm học mấy con hàng công nghệ "già cỗi nhưng đáng tin cậy" (Old Boring Technology). Những thứ mà mình chưa từng sờ vào bao giờ, dù chúng đã trường tồn được hơn 20 năm nay. Cảm giác nó sướng cực kỳ anh em ạ! Kiểu như mọi bug hay vấn đề quái thai nào mà mình chuẩn bị gặp phải thì thiên hạ đã giải quyết xong từ 8 đời tổ tông rồi, mình chỉ việc ung dung thừa hưởng và làm việc của mình thôi.
Từ lâu mình đã nghĩ việc cày cuốc một web framework phổ biến như Rails, Django hay Laravel là một ý tưởng siêu hay ho, nhưng cứ lần lữa mãi chưa làm được. Thế mà đợt vừa rồi, mình quyết định nhảy hố Django để build một cái website nhỏ. Mới vọc vạch được vài tháng thôi nhưng thấy "bánh cuốn" phết, dưới đây là vài dòng review nhanh cho anh em tham khảo!
Ít "phép thuật" hơn Rails
Hồi năm 2020, mình từng dành kha khá thời gian mày mò học Rails. Phải thừa nhận là nó rất xịn xò và mình thực sự muốn yêu thương con hàng này (cộng đồng Ruby siêu dễ thương luôn!). Thế nhưng có một vấn đề: nếu mình bỏ bẵng dự án Rails đó vài tháng không đụng vào, đến lúc quay lại, mình lú luôn và không nhớ nổi phải làm gì tiếp theo. Ví dụ như trong file routes.rb nó ghi vỏn vẹn resources :topics, chỉ nhìn vào đấy thì đố mà biết các route của topics được cấu hình chi tiết ở đâu, lại phải lục lọi trí nhớ hoặc đi tra cứu convention (quy ước) của nó.
Với mình, việc có thể "vứt xó" dự án vài tháng (hoặc cả năm) rồi sau đó quay lại code tiếp một cách mượt mà là cực kỳ quan trọng (hầu hết các project cá nhân của mình đều chạy theo kiểu này). Ở điểm này, Django mang lại cảm giác dễ thở hơn hẳn vì mọi thứ của nó đều rất tường minh (explicit).
Trong cái project Django nhỏ xinh của mình, dường như chỉ có đúng 5 file cốt lõi (ngoài mấy file settings linh tinh): urls.py, models.py, views.py, admin.py, và tests.py. Nếu mình muốn biết một cái gì đó nằm ở đâu (như file template HTML chẳng hạn), nó sẽ được tham chiếu một cách trực tiếp và rõ ràng từ một trong những file này. Không có ẩn ý hay phép thuật biến hóa gì ở đây cả!
Trang Admin có sẵn - Hàng khuyến mãi siêu xịn
Với dự án này, mình cần một giao diện quản trị (admin interface) để thỉnh thoảng vào chỉnh sửa hoặc xem nhanh data trong database bằng cơm. Django chuẩn bị sẵn cho chúng ta một trang Admin cực kỳ xịn mịn, và mình có thể tùy biến nó chỉ với vài dòng code ngắn ngủi.
Ví dụ, đây là một đoạn code cấu hình class admin của mình, dùng để định nghĩa xem những field nào sẽ hiện ra ở trang danh sách (list view), field nào dùng để search, và thứ tự sắp xếp mặc định của tụi nó:
@admin.register(Zine)
class ZineAdmin(admin.ModelAdmin):
list_display = ["name", "publication_date", "free", "slug", "image_preview"]
search_fields = ["name", "slug"]
readonly_fields = ["image_preview"]
ordering = ["-publication_date"]
Xài ORM cũng vui phết chứ đùa
Trước đây, thái độ của mình kiểu: "Ủa, ORM á? Ai thèm cơ chứ? Tự viết SQL thuần chả sướng và tối ưu hơn à!". Nhưng giờ vọc thử ORM của Django thì mình lại thấy thích mới chết. Nhìn cái cách Django dùng cú pháp hai dấu gạch dưới __ để đại diện cho một cú JOIN xem, trông thông minh vãi:
Zine.objects\
.exclude(product__order__email_hash=email_hash)
Nói nhỏ cho anh em biết là cái query ngắn ngủn phía trên nó lôi cả 5 bảng vào cuộc đấy: zines, zine_products, products, order_products, và orders. Để làm được điều này, mình chỉ cần khai báo cho Django biết là có một mối quan hệ ManyToManyField giữa "orders" và "products", và một cái ManyToManyField khác giữa "zines" và "products". Việc còn lại cứ để Django lo, nó tự biết cách móc nối các bảng này lại với nhau.
Tất nhiên là mình thừa sức tự gõ tay câu query SQL đó, nhưng viết kiểu product__order__email_hash rõ ràng là đỡ mỏi tay hơn hẳn, lại còn dễ đọc dễ hiểu. Thú thật là nếu tự viết SQL thuần (để vừa join 5 bảng vừa xử lý thêm vài logic linh tinh khác ngoài mấy cái join đó), chắc mình cũng phải mất một lúc để vắt óc suy nghĩ cấu trúc.
Hiện tại thì mình hoàn toàn không lo lắng gì về mặt performance của mấy câu query do ORM sinh ra cả, nên tạm thời cứ tận hưởng sự sung sướng này đã. Sau này có bị nó "hành" hay không thì tính sau!
Migration tự động - Sướng run người!
Một điểm cộng cực lớn khác đi kèm với ORM chính là cơ chế Migration!
Mỗi khi mình thêm, bớt, hoặc thay đổi bất kỳ field nào trong file models.py, Django sẽ tự động generate ra một script migration kiểu như migrations/0006_delete_imageblob.py.
Mình đoán là nếu thích thì mình hoàn toàn có thể nhảy vào edit mấy cái script đó. Nhưng cho đến giờ, mình cứ để mặc định rồi chạy lệnh áp dụng migration luôn, mọi thứ trơn tru không một tì vết. Cảm giác ảo diệu như có phép thuật thật sự!
Mình nhận ra là tính năng migration mượt mà này cực kỳ cứu cánh cho mình ở thời điểm hiện tại. Lý do là vì mình vẫn đang trong giai đoạn mò mẫm thiết kế database, cấu trúc dữ liệu thay đổi xoành xoạch như thời tiết vậy.
Docs viết siêu có tâm
Mình vốn có một thói quen xấu là cực kỳ lười đọc tài liệu hướng dẫn (docs). Nhưng lạ kỳ là mình lại cực kỳ tận hưởng việc đọc docs của Django. Điều này không phải tự dưng mà có đâu nhé: bác Jacob Kaplan-Moss từng có một bài talk từ PyCon 2011 chia sẻ sâu về "văn hóa viết tài liệu" siêu đỉnh của cộng đồng Django đấy.
Ví dụ như trang giới thiệu về models của họ liệt kê cực kỳ chi tiết và dễ hiểu những field phổ biến nhất mà bạn có thể sẽ cần dùng tới khi làm việc với ORM. Đọc tới đâu thấm tới đó!
Chơi hệ SQLite cho nhẹ đầu
Sau một vài trải nghiệm "đau thương" khi cố gắng vận hành Postgres mà không thể hiểu nổi chuyện quái gì đang xảy ra dưới hệ thống, mình quyết định quay xe, dùng SQLite cho tất cả các website nhỏ của mình. Và ôi thôi, nó nhẹ nhàng đầu óc gì đâu á! Việc backup giờ đây dễ như ăn kẹo: chỉ cần chạy một lệnh VACUUM INTO rồi copy cái file duy nhất đó đem đi cất là xong.
Mình đang config SQLite chạy trên production theo bài hướng dẫn này.
Mình nghĩ cấu hình này dư sức gánh được vì cái site này cùng lắm chỉ có tầm vài trăm lượt ghi (write) mỗi ngày là căng. Nó còn nhẹ nhàng hơn chán so với dự án Mess with DNS của mình (vốn có lượng write khủng khiếp hơn nhiều nhưng vẫn đang chạy phăm phăm trên 3 database SQLite khác nhau).
Triết lý "Batteries-included" (Có sẵn tận răng!)
Django mang đậm tư tưởng "batteries-included" (mang theo pin sẵn rồi, cứ thế mà xài thôi) – điều mà mình cực kỳ kết. Nếu mình cần cơ chế chống lỗi CSRF, cấu hình Content-Security-Policy, hay muốn gửi email? Có sẵn hết trong bộ cài đặt luôn, không cần cài cắm mệt mỏi!
Ví dụ, ở môi trường dev, mình muốn lưu toàn bộ email mà Django gửi ra thành một file local (để tránh việc lỡ tay gửi mail thật cho người dùng thật). Cấu hình việc này dễ ợt!
Mình chỉ cần ném đống này vào file settings/dev.py:
EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = BASE_DIR / "emails"
Còn khi lên production, mình đổi lại cấu hình SMTP trong file settings/production.py như thế này:
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.whatever.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = "xxxx"
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_API_KEY')
Cảm giác này sướng ở chỗ: sau này nếu mình muốn làm thêm bất kỳ tính năng cơ bản nào của một website, khả năng cao là Django đã build sẵn một giải pháp cực kỳ dễ dùng cho mình rồi.
File settings nhìn vẫn hơi "ngợp"
Thú thật là mình vẫn hơi rén mỗi khi nhìn vào file settings.py. Cách quản lý cấu hình của Django là ném một đống biến global vào chung một file. Mình cứ bị lo xa... lỡ như mình gõ typo (sai chính tả) một cái tên biến thì sao? Làm sao mà biết được nhỉ? Ví dụ lỡ tay gõ nhầm thành WSGI_APPLICATOIN = "config.wsgi.application" thay vì WSGI_APPLICATION thì có mà khóc thét.
Chắc do mình đã quen với việc được mấy con Python language server (LSP) trên IDE nhắc bài mỗi khi gõ sai chính tả rồi, nên giờ không có nó bảo kê trong mấy vụ này thấy hơi hoang mang style một chút.
Tạm thế đã nhé anh em!
Trước đây mình chưa từng deploy thành công một dự án nào sử dụng web framework thực thụ cả (hầu hết các trang web hiện tại của mình đều là một file binary Go duy nhất hoặc là static site tĩnh). Thế nên lần này mình cực kỳ hóng xem kết quả của chuyến phiêu lưu với Django này sẽ đi về đâu!
Vẫn còn cả một bầu trời kiến thức để mình tiếp tục cày cuốc, ví dụ như hệ thống validate Form hay cơ chế Authentication (xác thực) của Django, mình vẫn chưa sờ gáy tới nữa.
Tiện đây, hy vọng bài viết nhỏ này mang lại chút góc nhìn thú vị cho anh em nào đang tò mò về Django. Chúc anh em code vui và hẹn gặp lại ở những hành trình vọc vạch tiếp theo!
Comments
Please login to post a comment.