Setup Mypy for Django projects

After my last post "How to install a LSP server that supports Django" was shared, I got feedback that some fellows tried to install the LSP, but didn't get the autocomplete working as shown in my screenshot. So I continue with this article.

django-extra-attribute

People often miss the detail that the core power of an LSP server comes from the static type checker (or the compiler in case of compiled languages). When you write window. then hit the Tab key, the LSP server starts to suggest the attributes of the window object. But it can only know which attributes the window object has, if the type of the window variable is inferred successfully and correctly. The later job is done by static type checker, or concretely, Mypy.

So, for a Django project, how do you set up Mypy so type inference works? Basically, it's just like adding Mypy for type checking, but with more honesty. I use the word "honesty" because some projects added Mypy but the team members try to get the green "passed" status by making Mypy skip the type checking, ignoring the errors instead of really fixing them.

…

How to install a LSP server that supports Django

Before, when developing Django-based projects, I often use VS Code. Because VS Code is getting heavier and heavier (the installation is 1 GiB now), I need to move away from it. But the first thing is to find an independent LSP server that works well enough with Django. VS Code comes with Pylance, its LSP server for Python. But Pylance is proprietary, so for another code editor, I need a different solution.

When we do programming, LSP servers are great tools. They help improve productivity by enabling accurate autocomplete in code editors, allowing us to code faster and make less mistakes. They work best with languages having a strong type system (Rust and functional programming languages, like Gleam), because the type system lets us know, at any point, which type a variable has and what members it contains. For dynamic type languages, LSP servers are often based on static type checkers (because both need to draw type information from the source code). For Python, the situation is a bit hard, because Python is so dynamic and flexible that, its type annotations cannot cover all the cases to help type checkers and LSP servers infer the type of variables. It is especially true for Django. At the time of writing, Mypy is the type checker that supports Django the best. It means that, on the LSP server side, we need one that can take advantage of Mypy. Currently, there are many type checkers + LSP servers for Python, most of which are not written in Python:

  • Pyright: Written in TypeScript.
…

Define UI comprising keyboard Shortcut in Blueprint for modern GTK apps

In previous posts, "Define UI comprising Dropdown in Blueprint for modern GTK apps" and "Define UI comprising ListView in Blueprint for modern GTK apps", I presented how to use list widgets in Blueprint. Now we look at a different, but more compact topic, the keyboard shortcut.

In a desktop app, the user is expected to do a lot of work with the keyboard alone, not always reaching for the mouse. So a good app should have many keyboard shortcuts. For example, a Ctrl+V to paste, a Ctrl+S to save, an F1 to show help, etc. Most GUI toolkits have built-in support for this. GTK is no exception. There are two ways to assign a keyboard shortcut to an action in GTK 4:

  • The simplest one is the application's accelerator, set via gtk_application_set_accels_for_action(). You define the action on the application (with the app. prefix), then call that function with a list of accelerator strings. But this is not declarative, you have to write code.
  • A more flexible way is to use a Gtk.ShortcutController, to which you add one or more Gtk.Shortcut objects. Each Shortcut binds a trigger (a key combination) to an action. This is what we will learn in this post, because it is declarative and we can describe the shortcut in the Blueprint file alongside the rest of the UI.
…

journald-send - Library to help write logs to journald, for Python

In the last April, I made journald-send, to serve as replacement for systemd-python, for folks who want to write logs to journald, using native protocol.

It is a partial replacement, because it only offers the "write" part, not "read". That's enough because most of applications which want to talk with journald just need to "write". I made journald-send out of the frustration that systemd-python development seems to be stuck, the last release was on the beginning of 2023, when it is 2026 now, and the compatibility with Python 3.14 is uncertain. Even after I contributed some code to modernize the Python project structure, the core developers still seems to not rush to make a release.

I wrote [jounald-send] in Rust, aiming for Python 3.14 free-threaded (No GIL) mode. Because I only need to support "write" operation, I decide not to depend on the C libsystemd, and go further by using Rust pure libraries (rustix and memfd) to talk with Linux API. I learnt from tracing-journald for how to prepare data for journald protocol and which steps to do with the sockets. The difference is that tracing-journald is using libc and I use rustix, memfd.

After finishing journald-send, I updated my other libraries chameleon-log, structlog-journald to use journald-send under the hood. chameleon-log is for integrating logbook and structlog-journald is for integrating with structlog.

…

Thư viện Python tra cứu phường xã trước và sau sát nhập

Đã nửa năm từ sau sự thay đổi lớn về đơn vị hành chính Tháng 7 - 2025, mọi người vẫn còn khó khăn với việc đối chiếu dữ liệu trước và sau sát nhập. Vì vậy mình đã nâng cấp thư viện vietnam-provinces để hỗ trợ việc này.

Từ phiên bản 2026.2.0, bạn đã có thể truy cập dữ liệu phường xã cũ trong module legacy, ví dụ:

>>> from vietnam_provinces import legacy
>>> from rich import print
…

API tỉnh thành có dữ liệu chính thức sau đợt sát nhập

Tháng 7/2025, chính quyền có sự thay đổi mạnh về cấu trúc đơn vị hành chính, khi hủy bỏ cấp huyện và sáp nhập tỉnh với tỉnh, xã với xã. Tuy nhiên bảng mã cho các xã sau sát nhập vẫn chưa có chính thức sau nhiều tháng trời, chỉ tồn tại trong văn bản "Dự thảo". Cách đây mấy ngày, thì mình phát hiện dữ liệu đó đã được công bố chính thức trên website của Cục Thống kê nên đã cập nhật luôn thư viện vietnam-provinces và API Tỉnh thành Việt Nam.

Đợt sát nhập tỉnh thành này có vẻ cũng bao gồm cả việc tổ chức lại bộ máy hành chính Trung ương. Lần trước, cơ quan cung cấp dữ liệu bảng mã tỉnh thành là Tổng cục Thống kê", hoạt động tại tên miền gso.gov.vn, nhưng nay cơ quan đó là "Cục Thống kê", hoạt động tại tên miền nso.gov.vn.

…

Điểm mới của Python 3.14: Chế độ free-threading

Một điểm mới khác, khá quan trọng, của Python 3.14, nhưng không "đập vào mắt người dùng" là chế độ "free-threading". Đây là chế độ mà CPython tắt "Global Interpreter Lock" (GIL), một loại khóa trước đây dùng để ngăn chặn nhiều thread cùng truy cập, sửa đổi dữ liệu thuộc kiểu riêng của CPython. Nay với chế độ "free-threading" thì các thread được chạy song song thoải mái hơn (tốc độ xử lý của ứng dụng đa luồng cũng tăng lên).

Nếu bạn viết code Python, không cần phải quan tâm vì ở mức độ này không nhìn thấy GIL. Chỉ khi bạn viết extension cho Python bằng ngôn ngữ biên dịch (C, C++, Rust) thì mới phải động vào GIL. Khi CPython gỡ bỏ GIL, tương tự như ngã tư bỏ đi cảnh sát đứng phân luồng, thì tác giả các extension này phải tự đảm bảo code mình là thread-safe, tự áp dụng các phương tiện, chiêu thức khác để tránh code mình bị crash, deadlock trong môi trường đa luồng. Điều này lại là cơ hội tỏa sáng cho các extension viết bằng Rust. Một trong các điểm "ăn tiền" của Rust là "fearless concurrency". Rust có các luật kiểm tra ownership, lifetime chặt chẽ, có các phương tiện dành cho lập trình đa luồng giúp bạn tránh tối đa các lỗi hay gặp, khó mò trong lập trình đa luồng.

Free-threading

Mình có một extension, viết bằng Rust, để làm cho nó tương thích với "free-threading" thì cực kỳ dễ, chỉ cần khai báo gil_used = false, vì vốn từ đầu nó đã chạy mà không cần "xin" GIL rồi.

...

structlog-journald, ghi log vào journald

Hôm nay mình phát hành thư viện structlog-journald v0.5.0. Thư viện này tận dụng lợi thế của journald để giúp debug hệ thống multi-tenant dễ dàng hơn. Đây là những hệ thống phục vụ nhiều khách hàng, với cách làm thông thường thì log của nhiều khách hàng sẽ trộn lẫn với nhau gây khó khăn cho việc debug. Thư viện này cho phép gắn thông tin phụ (như ID khách hàng) khi ghi log rồi sau đó khi xem log bằng journalctl có thể lọc theo thông tin phụ đó. Bằng cách đó ta có thể tập trung vào một đối tượng cụ thể để truy vết.

Minh họa:

demo

...

Đồ chơi để thấy GraphQL đỡ phiền

GraphQL là một dạng thiết kế HTTP API được dùng rộng rãi. Mặt lợi của nó thì không cần bàn. Tuy nhiên mình và có thể các bạn cũng thấy hơi phiền vì nó dài dòng. Bài này sẽ giới thiệu một số phương tiện phần mềm để làm việc với nó thoải mái hơn, ở phía client.

Python: Cách dùng Pydantic để kiểm tra hợp lệ

Lấy ví dụ API của BirdWeather. Đây là kho dữ liệu của các trạm thu thập tiếng chim hót, phục vụ nghiên cứu nhận dạng chim từ tiếng hót. Ta sẽ gọi vào truy vấn stations để lấy danh sách các trạm. Một response mẫu sẽ trông như sau:

...

Triển khai tự động ứng dụng web Python

Gần đây nghe sự cố máy chủ DeepSeek bị lộ dữ liệu do để mở cổng database toang hoác, làm tôi nhớ đến cách triển khai ứng dụng web của mình, trong đó mình đóng cổng database luôn, chỉ cho truy cập qua Unix domain socket (dạng file), và cũng không cần tạo password, không cần nhớ, không cần giấu password. Thủ thuật này đã được nhắc đến trong một bài blog khác bằng tiếng Anh, nay dịch ra cho anh em tham khảo. Bài viết đó nói về một chủ đề rộng hơn là "cách triển khai ứng dụng web Python một cách tự động".

Gần đây tôi thấy một câu hỏi từ một đồng nghiệp Python, làm thế nào để triển khai ứng dụng Django mà không cần phải SSH thủ công vào máy chủ và chạy các lệnh. Phong cách này là "single server deployment". triển khai trên một máy chủ duy nhất, nơi bạn đặt tất cả các thành phần, từ mã ứng dụng, cơ sở dữ liệu, đến các tệp tĩnh, tệp media, trên cùng một máy chủ. Không có Docker tham gia. Với kiểu triển khai này, chúng ta sẽ cần một cách nào đó để cung cấp phiên bản mới của ứng dụng mỗi khi mã mới được đẩy lên nhánh "release" của kho lưu trữ Git.

Tại sao cần tự động hóa? Vì làm đi làm lại những việc này rất nhàm chán:

  • SSH vào máy chủ, cd vào thư mục cài đặt.
...