Chuyển đến nội dung chính

Python FastHTML: Hướng dẫn cho người mới bắt đầu kèm ví dụ

Tìm hiểu FastHTML, thư viện Python để tạo trang web động. Bao gồm ví dụ ứng dụng thực tế.
· 15 phút đọc

Khám phá cùng AI

Xây dựng giao diện web hiện đại bằng Python thường đồng nghĩa với việc phải xử lý nhiều lớp, công cụ template, công cụ JavaScript và framework front-end chỉ để chạy một UI cơ bản. FastHTML đưa ra một hướng tiếp cận tập trung hơn: một framework tối giản, ưu tiên Python, giúp đơn giản hóa phát triển bằng cách cho phép bạn định nghĩa giao diện trực tiếp trong mã, không cần rời khỏi ngôn ngữ hay quản lý thêm độ phức tạp.

Bài viết này khám phá cách FastHTML hoạt động, các nguyên tắc thiết kế cốt lõi và cách xây dựng ứng dụng thực tế với nó—từ trang đơn giản đến các giao diện tương tác hoàn chỉnh, định hướng dữ liệu.

Nếu bạn muốn củng cố nền tảng phát triển backend trước khi bắt đầu, tôi khuyến nghị xem hướng dẫn phát triển backend bằng Python trên DataCamp để có tổng quan về các khái niệm và công cụ web cốt lõi.

FastHTML là gì?

FastHTML là một framework Python gọn nhẹ được thiết kế để đơn giản hóa phát triển giao diện web. Nó giải quyết các thách thức phổ biến trong phát triển, kiểm thử và hiệu năng bằng cách loại bỏ nhu cầu kiến thức JavaScript sâu hoặc quản lý nhiều tệp template.

Nhiều lập trình viên Python muốn tạo giao diện web mà không cần dấn thân vào sự phức tạp của một stack JavaScript đầy đủ. FastHTML đáp ứng nhu cầu này, cho phép lập trình viên định nghĩa route và các thành phần HTML chỉ với vài dòng mã Python súc tích.

Vượt ra ngoài giao diện cơ bản, nhà phát triển có thể dễ dàng mở rộng ứng dụng xây bằng FastHTML bằng cách bổ sung các tính năng như xác thực, bộ nhớ đệm, tích hợp cơ sở dữ liệu và tùy biến kiểu dáng, từ đó nâng cao đáng kể chức năng và trải nghiệm người dùng.

Tính năng và lợi ích của FastHTML

FastHTML có nhiều tính năng và lợi ích. Nó vượt qua nhiều thách thức về phát triển, kiểm thử và hiệu năng.

FastHMTL có nhiều tính năng và lợi ích.

  • Phát triển chỉ với Python: Bạn không cần chức năng JavaScript bổ sung, chỉ cần Python. Kết quả là dự án gọn nhẹ với ít tệp và ít boilerplate hơn.
  • Phụ thuộc tối thiểu: FastHTML chỉ dựa vào một vài thư viện bên ngoài, nên việc nâng cấp đơn giản và bảo trì ít phức tạp hơn.
  • Bảo mật. Ít phụ thuộc hơn đồng nghĩa với bề mặt tấn công nhỏ hơn. 
  • Stack client/server thống nhất: Dùng một ngôn ngữ và framework cho cả logic và UI giảm chuyển đổi ngữ cảnh, nhờ đó tăng tốc phát triển.
  • Phần tử HTML như đối tượng Python gốc: FastHTML cho phép bạn dùng các phần tử HTML như đối tượng Python thông qua thuộc tính HTMX mà không cần JavaScript tùy chỉnh.
  • Xử lý yêu cầu bất đồng bộ: FastHTML hỗ trợ xử lý yêu cầu bất đồng bộ, mang lại độ trễ thấp và khả năng đồng thời cao.
  • Triển khai linh hoạt: Ứng dụng hoàn chỉnh có thể triển khai trên bất kỳ nền tảng nào hỗ trợ Python.

FastHTML giảm nhẹ sự phức tạp vốn có của phát triển UI web, như quản lý tệp template riêng, script hỗ trợ và pipeline tài nguyên. Độ phức tạp kiểm thử giảm đáng kể nhờ stack Python thống nhất cho phép đơn giản hóa các giai đoạn kiểm thử backend, frontend và end-to-end.

Nguyên tắc kiến trúc cốt lõi

FastHTML được xây dựng dựa trên các nguyên tắc cốt lõi: lớp trừu tượng HTML theo phong cách Pythonic, tích hợp tiêu chuẩn ASGI và tính tương tác dựa trên HTMX.

Lớp trừu tượng HTML theo phong cách Pythonic

FastHTML biểu diễn mọi phần tử HTML tiêu chuẩn dưới dạng hàm Python tương ứng. Chẳng hạn thẻ HTML <div> được phản chiếu bằng hàm Python Div(...), <a> trở thành A(..., href=...) v.v. 

Các đối số vị trí truyền vào hàm phần tử Python sẽ được render thành phần tử con trong cấu trúc HTML kết quả. Ví dụ,

Div(
	P("Hello, world!"),
	Ul(Li("one"), Li("two"))
)

sẽ tạo ra HTML sau: 

<div>
  <p>Hello, world!</p>
  <ul>
    <li>one</li>
    <li>two</li>
  </ul>
</div>

Các đối số từ khóa trở thành thuộc tính HTML. Ví dụ, đoạn Python

A("Docs", href="/docs", cls="button", hx_get="/info")

được render thành

<a href="/docs" class="button" hx-get="/info">Docs</a>

Lưu ý từ khóa cls ánh xạ tới thuộc tính class trong HTML. Dấu gạch dưới trong tên thuộc tính (hx_get) được chuyển thành dấu gạch nối (hx-get). 

FastHTML trì hoãn việc tuần tự hóa, cho phép route trả về đối tượng Python thay vì chuỗi HTML thô. Framework chỉ chuyển cây đối tượng Python sang HTML ở bước cuối, ngay trước khi gửi phản hồi. Thiết kế này giúp logic gọn gàng, không phải thao tác chuỗi thủ công.

FastHTML mang lại lợi ích của templating an toàn kiểu và xử lý thuộc tính, giúp mã rõ ràng và dễ bảo trì. API phần tử và thuộc tính xuất hiện trong định nghĩa hàm hoặc lớp, khiến mã tự giải thích. Tên an toàn với Python (từ hx-post sang hx_post) tránh việc thao tác chuỗi thủ công.

Việc refactor an toàn và đáng tin cậy hơn. Đổi tên tham số sẽ tự động cập nhật nơi sử dụng. Hơn nữa, unit test có thể khởi tạo và kiểm tra trực tiếp đối tượng thành phần, không cần phụ thuộc vào regex trên HTML đã render.

Tích hợp ASGI (Asynchronous Server Gateway Interface)

FastHTML tích hợp với ASGI, một tiêu chuẩn do cộng đồng Python xây dựng cho phép giao tiếp không chặn, hướng sự kiện giữa máy chủ web và ứng dụng. ASGI cung cấp năng lực cho các framework web Python hiện đại bằng cách hỗ trợ thao tác bất đồng bộ ngay tại lõi của stack web.

Máy chủ web như Uvicorn tuân thủ đặc tả ASGI, đảm bảo khả năng tương thích và khả năng mở rộng. Các framework như Starlette và FastHTML xây dựng trên ASGI để cung cấp routing, middleware và API cấp cao mạnh mẽ.

Kiến trúc này mang lại khả năng đồng thời cao, hỗ trợ sẵn cho HTTP, WebSocket và server-sent events, cùng xử lý yêu cầu hướng sự kiện hiệu quả. Bằng việc dùng vòng lặp sự kiện asyncio, ứng dụng ASGI tránh chi phí một luồng hệ điều hành cho mỗi kết nối, cho phép vài luồng xử lý hàng nghìn khách hàng. Đối tượng scope tiêu chuẩn hóa và thiết kế không chặn cho phép handler tạm dừng cho I/O mà không làm chậm yêu cầu khác.

Tính tương tác dựa trên HTMX

Với thư viện HTMX, bạn có thể mở rộng các thuộc tính HTML tiêu chuẩn bằng các thuộc tính hx-*. Những phần tử này cho phép gửi yêu cầu HTTP và thay thế nội dung trang một cách động bằng các mảnh HTML máy chủ trả về. Bạn không cần JavaScript tùy chỉnh. 

Bắt đầu với FastHTML

Bắt đầu với FastHTML rất đơn giản. Chúng tôi đã phác thảo các bước chính trong các phần dưới đây. 

Cài đặt và thiết lập

Để cài đặt FastHTML, dùng pip install python-fasthtml.

Ứng dụng đầu tiên

Hãy xây một ứng dụng đơn giản hiển thị tiêu đề và thông điệp.

from fasthtml.common import FastHTML, serve, Div, H1, P

app = FastHTML()

@app.get("/")
def home():
    return Div(
        H1("Welcome to FastHTML"),
        P("Hello, world!")
    )

if __name__ == "__main__":
    serve()

Chạy tệp bằng cách gõ python app.py trong terminal. 

 

Nhấn giữ Ctrl và bấm vào liên kết để mở ứng dụng. Bạn sẽ thấy một trang:

Định nghĩa route

Hãy thêm trang About vào ứng dụng. Dùng đoạn mã sau:

from fasthtml.common import FastHTML, serve, Div, H1, P, A

app = FastHTML()

@app.get("/")
def home():
    return Div(
        H1("Welcome to FastHTML"),
        P("Hello, world!"),
        A("About", href="/about")
    )

@app.get("/about")
def about():
    return Div(
        H1("About"),
        P("This is the about page."),
        A("Home", href="/")
    )

if __name__ == "__main__":
    serve()

Dòng A("About", href="/about") tạo liên kết từ trang chủ đến trang giới thiệu. Decorator @app.get("/about") định nghĩa route cho trang giới thiệu.

Triển khai cơ bản

Trong FastHTML, các mẫu UI có thể tái sử dụng được đóng gói trong những hàm Python đơn giản. Các hàm này trả về các đối tượng thành phần lồng nhau, cho phép bạn coi các widget như Card hoặc Navbar là đối tượng có thể gọi. 

Định nghĩa markup, thuộc tính và kiểu dáng ở một nơi đảm bảo tính nhất quán trên toàn ứng dụng. Khi bạn import và sử dụng các hàm này, mọi thay đổi về trực quan hoặc hành vi sẽ tự động lan tỏa.

Cách tiếp cận này giảm lặp lại mã, khiến frontend của bạn dễ kiểm thử và refactor như bất kỳ mô-đun Python nào.

Để minh họa, hãy tạo một trang hiển thị hai thẻ (card) đơn giản.

from fasthtml.common import *

def Card(title: str, body: str):
    children = [
        H2(title, cls="card-title"),
        P(body, cls="card-body")
    ]
    return Div(
        *children,
        cls="card",
        style="background- border-radius: 0.5rem;"
    )

app = FastHTML()

@app.get("/")
def home():
    return Div(
        Card("Welcome", "A welcome card."),
        P(''),
        Card("A Second Card", "This is another card."),
        cls="page"
    )

Hàm Card nhận chuỗi title và body làm đối số và trả về một phần tử thẻ với kiểu dáng cơ bản. Trong route home, widget này được dùng hai lần mà không cần lặp mã. Chúng ta định nghĩa Card một lần và tái sử dụng theo nhu cầu, đảm bảo markup và kiểu dáng nhất quán trên toàn ứng dụng.

Có một số lợi ích khi tạo widget UI theo cách này.

  • Giảm trùng lặp: Thiết lập markup và kiểu dáng một lần, rồi tái sử dụng thành phần ở bất cứ đâu. Cập nhật hoặc sửa lỗi sẽ tự động lan tỏa.
  • Thiết kế UI nhất quán: Mỗi thể hiện của thành phần giữ nguyên cấu trúc, class và hành vi. Điều này củng cố vẻ ngoài và cảm nhận đồng nhất trên toàn ứng dụng.
  • Bảo trì đơn giản: Codebase nhỏ hơn, tuân thủ DRY, đồng nghĩa với ít tệp cần quản lý, ít boilerplate và phát triển hiệu quả hơn.

Sử dụng nâng cao

Phần này khám phá các kỹ thuật nâng cao trong FastHTML, bao gồm xử lý form, xác thực và mẫu phản hồi lỗi. Bằng cách tận dụng lớp Python và thành phần có cấu trúc, bạn có thể xây dựng form mạnh mẽ, thân thiện với người dùng đồng thời vẫn giữ mã sạch và dễ kiểm thử.

Xử lý form và xác thực

FastHTML đơn giản hóa xử lý form bằng cách tự động tạo form HTML từ lớp Python và cung cấp liên kết dữ liệu trực quan để xử lý submit form. 

Ví dụ, xem đoạn mã sau.

from fasthtml.common import *
from dataclasses import dataclass

@dataclass
class Profile:
    name:str;
    email:str;
    age:int

profile_form = Form(method="post", action="/profile")(
        Fieldset(
            Label("Name", Input(name="name")),
            Label("Email", Input(name="email")),
            Label("Age", Input(name="age")),
        ),
        Button("Submit", type="submit"),
    )

# Instantiate app
app = FastHTML()

# GET / serves the form (FastHTML will serialize the component to HTML)
@app.get("/")
def home():
    return profile_form

# Simple POST handler to echo back submitted data
@app.post("/profile")
def profile(data: Profile):
    return Div(
        H1("Profile Submitted"),
        P(f"Name: {data.name}"),
        P(f"Email: {data.email}"),
        P(f"Age: {data.age}")
    )

Đoạn mã này tạo ra HTML sau cho form. FastHTML tự động phân tích dữ liệu form vào đối tượng Profile, giả định tên trường tương thích. Ở tầng bên dưới, điều này có thể dựa vào cơ chế phân tích form kiểu Starlette và một lớp xác thực tùy chỉnh.

<form enctype="multipart/form-data" method="post" action="/profile">
	<fieldset>
	<label>Name<input name="name"></label>
	<label>Email<input name="email"></label>
	<label>Age<input name="age"></label>
</fieldset>

	<button type="submit">Submit</button>
</form>

Khi form được gửi, FastHTML phân tích dữ liệu vào đối tượng Profile. Route profile sau đó trả về trang xác nhận, hiển thị các giá trị đã gửi trực tiếp từ đối tượng data. Cách này đơn giản hóa xử lý form, giảm boilerplate và đảm bảo kiểu dữ liệu mạnh trên toàn ứng dụng.

Luôn là ý tưởng hay khi xác thực đầu vào form. Thêm logic xác thực bằng cách viết lại route /profile như sau.

@app.post("/profile")
def submit_profile(data: Profile):
    # Form validation
    if not data.name.strip():
        raise HTTPException(status_code=400, detail="Name is required")
    if not data.email.strip() or "@" not in data.email:
        raise HTTPException(status_code=400, detail="A valid email is required")
    if data.age < 0:
        raise HTTPException(status_code=400, detail="Age must be non-negative")
    
    # If validation passes, render the result
    return Div(
        H1("Profile Submitted"),
        P(f"Name: {data.name}"),
        P(f"Email: {data.email}"),
        P(f"Age: {data.age}")
    )

Nếu thiếu name, thiếu email hoặc age âm, người dùng sẽ nhận thông báo lỗi rõ ràng. Bằng cách raise HTTPException với mã trạng thái 400, ứng dụng truyền đạt lỗi xác thực cụ thể, giúp người dùng sửa đầu vào trước khi gửi lại form.

Một cách chắc chắn hơn để xử lý dữ liệu thiếu hoặc không hợp lệ là kiểm tra lỗi tường minh và cung cấp phản hồi thân thiện. Ví dụ, viết lại mã như sau.

from fasthtml.common import *
from dataclasses import dataclass

@dataclass
class Profile:
    name: str
    email: str
    age: int

def profile_form(data=None, errors=None):
    data   = data   or {}
    errors = errors or {}
    return Form(
        Fieldset(
            Label(
                "Name",
                Input(
                    name="name",
                    value=data.get("name", ""),
                    placeholder="Your name"
                )
            ),
            Small(errors.get("name", ""), cls="error-text"),

            Label(
                "Email",
                Input(
                    name="email",
                    type="email",
                    value=data.get("email", ""),
                    placeholder="[email protected]"
                )
            ),
            Small(errors.get("email", ""), cls="error-text"),

            Label(
                "Age",
                Input(
                    name="age",
                    type="number",
                    value=str(data.get("age", "")),
                    placeholder="Age"
                )
            ),
            Small(errors.get("age", ""), cls="error-text"),
        ),
        Button("Submit", type="submit")
    , method="post", action="/profile", id="profile-form", hx_swap="outerHTML")

app = FastHTML()

@app.get("/")
def home():
    return Div(
        H1("Create Your Profile"),
        profile_form()
    )

@app.post("/profile")
async def submit_profile(request):
    form = await request.form()
    data = {
        "name":  form.get("name", "").strip(),
        "email": form.get("email", "").strip(),
    }
    errors = {}

    # Validate name
    if not data["name"]:
        errors["name"] = "Name is required. "

    # Validate email
    if not data["email"]:
        errors["email"] = "Email is required. "
    elif "@" not in data["email"]:
        errors["email"] = "Enter a valid email address."

    # Validate age
    age_raw = form.get("age", "").strip()
    try:
        age = int(age_raw)
        if age < 0:
            raise ValueError()
        data["age"] = age
    except ValueError:
        errors["age"] = "Age must be a non-negative integer. "

    if errors:
        # re-render form with submitted values and error messages
        return Div(
            H1("Create Your Profile"),
            profile_form(data, errors)
        )

    # Success path
    profile = Profile(**data)
    return Div(
        H1("Profile Submitted"),
        P(f"Name: {profile.name}"),
        P(f"Email: {profile.email}"),
        P(f"Age: {profile.age}")
    )

if __name__ == "__main__":
    serve()

Nếu người dùng bỏ qua trường bắt buộc hoặc nhập không hợp lệ, họ sẽ thấy form được render lại với các giá trị đã gửi và thông điệp lỗi phù hợp hiển thị cạnh từng trường. Cách tiếp cận này cải thiện trải nghiệm bằng cách chỉ rõ điều cần sửa.

Khi bạn đã điền đầy đủ và gửi, bạn sẽ thấy màn hình tương tự như sau.

Xác thực và quản lý phiên

Triển khai luồng xác thực

Trong FastHTML, dữ liệu phiên được quản lý qua đối tượng request.session, hoạt động như một từ điển Python. Bạn có thể lưu dữ liệu vào phiên bằng cách đặt cặp khóa-giá trị, ví dụ session['user_id'] = 123. Để truy xuất dữ liệu phiên, dùng read (user_id = session.get('user_id')). Để xóa toàn bộ dữ liệu phiên, gọi session.clear().

Ở tầng nền, FastHTML tuần tự hóa từ điển phiên vào một cookie đã ký, tồn tại qua nhiều yêu cầu. Cách này cho phép bạn quản lý xác thực người dùng và trạng thái phiên bằng các mẫu quen thuộc trong Python.

Phác thảo xây dựng quy trình xác thực

Để xây dựng một quy trình xác thực, hãy làm theo các bước sau.

  1. Cấu hình phiên: Thêm SessionMiddleware với secret_key mạnh. Khi đã cấu hình, request.session khả dụng trong mọi handler.
  2. Mô hình người dùng và xử lý mật khẩu: Định nghĩa lược đồ người dùng (dùng dataclass, mô hình Pydantic hoặc ORM) bao gồm username và password_hash. Dùng hàm băm (ví dụ hashlib, pbkdf2_hmac, bcrypt) để lưu và xác minh mật khẩu.
  3. Luồng đăng ký*: Tạo route GET /register để render form đăng ký. * Dùng POST /register để xác thực đầu vào, băm mật khẩu, lưu bản ghi người dùng, đặt session['user_id'], và chuyển hướng tới trang bảo vệ hoặc dashboard.
  4. Luồng đăng nhập*: Tạo route GET /login để hiển thị form đăng nhập.* Dùng POST /login để xác minh thông tin. Thành công thì ghi session['user_id'] và chuyển hướng; thất bại thì render lại form kèm thông báo lỗi.
  5. Bảo vệ route: Tạo hàm trợ giúp hoặc decorator kiểm tra session.get('user_id'). Nếu người dùng chưa xác thực, chuyển hướng đến /login; nếu không thì cho phép truy cập route được yêu cầu.
  6. Đăng xuất: Trong route GET /logout, gọi session.clear()` để xóa dữ liệu phiên và chuyển hướng người dùng về trang đăng nhập hoặc trang chủ.

Tích hợp cơ sở dữ liệu

ORM (Object-Relational Mapper) ánh xạ lớp với bảng cơ sở dữ liệu, cho phép bạn truy vấn dữ liệu bằng đối tượng gốc thay vì SQL thuần. Các lựa chọn phổ biến gồm SQLAlchemy và ORM của Django. 

FastHTML có giao diện “tương tự ORM” tích hợp với bất kỳ ORM hoặc thư viện truy vấn Python hỗ trợ async nào. Mặc định dùng SQLite nhưng có thể tích hợp với bất kỳ backend cơ sở dữ liệu. Ví dụ, xem đoạn mã sau.

# Database setup (SQLite by default, but backend can change)
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy import Column, Integer, String, select
from fasthtml.common import *

DATABASE_URL = "sqlite+aiosqlite:///./test.db"  # Change backend here (e.g., PostgreSQL)

engine = create_async_engine(DATABASE_URL, echo=True)
SessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
Base = declarative_base()

# ORM model
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    name = Column(String)

# FastHTML app
app = FastHTML()

@app.get("/")
async def list_users():
    async with SessionLocal() as session:
        result = await session.execute(select(User))
        users = result.scalars().all()
    
    return Div(
        H1("Users"),
        Ul(*[Li(user.name) for user in users])
    )

if __name__ == "__main__":
    import asyncio
    async def init_db():
        async with engine.begin() as conn:
            await conn.run_sync(Base.metadata.create_all)
    asyncio.run(init_db())
    serve()

Trong ứng dụng FastHTML, bạn truy vấn dữ liệu ở lớp cơ sở dữ liệu bạn chọn, rồi truyền kết quả vào các thành phần FastHTML để render. Ví dụ, sau khi lấy bản ghi từ cơ sở dữ liệu, bạn có thể lặp qua chúng trong handler và xây dựng cấu trúc HTML như bảng, danh sách hoặc thẻ tùy chỉnh.

Các thực hành tốt vẫn áp dụng: chỉ chọn trường cần thiết, lọc và sắp xếp ở cấp cơ sở dữ liệu, và phân trang tập kết quả lớn. FastHTML giúp bạn tập trung xây dựng frontend sạch, động trong khi để việc xử lý dữ liệu cho các công cụ phù hợp nhất với dự án.

Chiến lược tối ưu hiệu năng

Có nhiều cách để bạn đạt kết quả tốt nhất khi dùng FastHTML. Chúng tôi đã nêu một số khuyến nghị dưới đây. 

Cơ chế bộ nhớ đệm

Bộ nhớ đệm cải thiện hiệu năng bằng cách tránh công việc lặp lại ở các lớp khác nhau của ứng dụng. Ở cấp trình duyệt và CDN, dùng header cache control để giữ tài nguyên tĩnh như hình ảnh, script và stylesheet. 

Bạn có thể lưu đệm toàn bộ phản hồi route hoặc phần tốn kém trong framework web. Trong ứng dụng FastHTML, bạn lưu đệm toàn bộ phản hồi route hoặc các thành phần đắt đỏ, đảm bảo yêu cầu lặp lại trả về nhanh mà không cần truy vấn lại cơ sở dữ liệu hay tạo lại template.

Trong Python, bạn có thể triển khai bộ nhớ đệm ở cấp hàm bằng decorator. Ví dụ, decorator functools.lru_cache tích hợp có thể memoize một hàm trợ giúp lấy dữ liệu người dùng. Chẳng hạn, bạn có thể dùng decorator này để lưu đệm các cuộc gọi cơ sở dữ liệu:

from functools import lru_cache

@lru_cache(maxsize=64)
def fetch_user_profile(user_id):
    # simulate an expensive database call
    return db.get_user(user_id)

@app.get("/profile/{user_id}")
def profile(user_id: int):
    profile = fetch_user_profile(user_id)
    return Div(P(profile.name), P(profile.email))

Hàng đợi tác vụ bất đồng bộ

Ứng dụng web giữ độ phản hồi bằng cách chuyển các tác vụ tốn thời gian ra khỏi vòng đời yêu cầu. Thay vì chặn máy chủ khi tạo báo cáo, gửi email hoặc xử lý dữ liệu, các tác vụ này được đưa vào hàng đợi và chạy nền. 

Với cách tiếp cận này, ứng dụng gửi phản hồi ngay cho người dùng trong khi worker chạy ở tiến trình hoặc luồng riêng xử lý tác vụ đã xếp hàng một cách bất đồng bộ.

FastHTML hỗ trợ thực thi tác vụ nền bằng cách tích hợp với BackgroundTasks của Starlette. Dưới đây là ví dụ minh họa cách gửi email chào mừng sau khi người dùng đăng ký.

from fasthtml.common import FastHTML, serve, Div, Form, Input, Button
from starlette.background import BackgroundTasks

app = FastHTML()

def send_welcome_email(email: str):
    # expensive or time consuming work
    ...

@app.post("/signup")
def signup(background_tasks: BackgroundTasks, request):
    form = await request.form()
    email = form["email"]
    # schedule the email task
    background_tasks.add_task(send_welcome_email, email)
    return Div("Thanks for signing up! You will receive an email shortly.")

Ứng dụng thực tế

FastHTML là framework linh hoạt có thể vận hành nhiều loại ứng dụng web. Hãy xem cách bạn có thể tiếp cận xây dựng một nền tảng thương mại điện tử và một bảng điều khiển dữ liệu bằng FastHTML.

Bản thiết kế nền tảng thương mại điện tử

Hãy xây dựng một nền tảng thương mại điện tử với FastHTML. Bắt đầu bằng cách mô hình hóa dữ liệu chính của bạn thành các lớp ORM hoặc dataclass Python: sản phẩm, người dùng và mục giỏ hàng. 

Tạo trang danh sách sản phẩm lặp qua các bản ghi sản phẩm. Với mỗi sản phẩm, dùng một thành phần Python có thể tái sử dụng, như Card, để hiển thị hình ảnh, tên, giá và nút "Add to Cart". Nút này bao gồm các thuộc tính HTMX như hx_post và hx_target, cho phép gửi yêu cầu thêm mục vào giỏ hàng phiên của người dùng mà không cần tải lại toàn bộ trang.

Bản thân giỏ hàng được lưu trong từ điển session của người dùng trên máy chủ. Trong phần đầu trang, bao gồm một thành phần tóm tắt giỏ hàng cập nhật động bằng HTMX bất cứ khi nào mục được thêm hoặc xóa. 

Trang giỏ hàng đọc dữ liệu phiên để render từng mục cùng tổng tiền. Trang cũng cung cấp form thanh toán kết nối tới một lớp Python để xác thực. Khi người dùng gửi form, ứng dụng tạo bản ghi đơn hàng và xóa giỏ hàng trong phiên.

Triển khai bảng điều khiển dữ liệu

Một bảng điều khiển dữ liệu trong FastHTML kết hợp các thành phần Python với nguồn dữ liệu của bạn, dùng HTMX cho tính tương tác và cập nhật thời gian thực. Logic backend của bạn (ví dụ, hàm trợ giúp async, tiện ích CRUD có lưu đệm, hoặc truy vấn ORM) truy xuất dữ liệu cần thiết. 

Từ đó, bạn thiết kế một trang với các widget có thể tái sử dụng. Chúng có thể gồm điều khiển lọc (như dropdown, bộ chọn ngày hoặc ô tìm kiếm) để tinh chỉnh truy vấn, thẻ KPI để hiển thị chỉ số chính, bảng dữ liệu để liệt kê bản ghi, hoặc nhúng biểu đồ để trực quan hóa xu hướng và so sánh. 

Mỗi widget được viết bằng mã Python gốc, thường là Div, Table hoặc thành phần Card tùy chỉnh. FastHTML tự động chuyển các đối tượng này thành HTML khi trả về phản hồi.

HTMX giúp bảng điều khiển trở nên tương tác. Ví dụ, widget lọc có thể dùng hx_get và hx_post để yêu cầu dữ liệu đã lọc từ máy chủ, cập nhật động bảng hoặc biểu đồ mà không cần tải lại toàn bộ trang. 

Phân tích so sánh với các framework truyền thống

FastHTML khác biệt so với các framework truyền thống như Django và Flask bằng cách hợp lý hóa cả phát triển lẫn hiệu năng. Hãy xem nó so sánh như thế nào qua các yếu tố chính như thời gian thiết lập, hiệu quả mã và điểm chuẩn hiệu năng.

Tốc độ phát triển

FastHTML có hai lợi thế chính so với các framework như Django và Flask: thời gian thiết lập và hiệu quả mã.

Thời gian thiết lập

Cách tiếp cận “đủ pin” của Django yêu cầu vài bước trước khi bạn có thể phục vụ trang đầu tiên: cài gói, chạy django-admin startproject, cấu hình settings và định nghĩa một app. Thường cần nhiều tệp và rất nhiều boilerplate trước khi bạn viết bất kỳ logic thực sự nào.

Flask gọn nhẹ hơn. Sau khi pip install, bạn có thể viết vài route trong một tệp. Tuy nhiên, bạn vẫn cần cấu hình template Jinja, thư mục static và thêm JavaScript cho tương tác.

Với FastHTML, thiết lập là tối thiểu.

  1. Chạy pip install python-fasthtml uvicorn.
  2. Định nghĩa route và các thành phần HTML theo phong cách Pythonic. Bạn có thể làm việc này trong một tệp duy nhất.
  3. Gọi serve().

Không cần engine template riêng hay cấu hình thư mục static. Bạn có thể bắt tay xây dựng ngay.

Hiệu quả mã

Với Django, ngay cả trang “Hello, world” đơn giản cũng cần nhiều tệp: views.py, urls.py, settings.py, templates/hello.html, cùng scaffold ORM và admin.

Flask đơn giản hóa xuống một tệp, nhưng bạn vẫn phải viết HTML thủ công trong template Jinja hoặc chuỗi inline, và JavaScript cho tương tác.

FastHTML cho phép bạn định nghĩa UI dưới dạng đối tượng Python nên không cần chuyển đổi tệp hay ngôn ngữ. HTMX xử lý tương tác theo cách khai báo mà không cần script tùy chỉnh. Kết quả là ít dòng mã hơn, không cần template riêng hay pipeline tài nguyên tĩnh, và một bề mặt kiểm thử duy nhất cho cả markup và hành vi.

Điểm chuẩn hiệu năng

Các nghiên cứu benchmark cho thấy framework bất đồng bộ vượt trội framework đồng bộ dưới tải đồng thời cao. Chẳng hạn, trong so sánh hiệu năng giữa Flask, Django, Quart và FastAPI, các framework bất đồng bộ (Quart và FastAPI) xử lý nhiều yêu cầu mỗi giây hơn đáng kể so với các đối thủ đồng bộ. 

Điều này được quy cho cơ chế xử lý yêu cầu không chặn, cho phép chúng quản lý nhiều yêu cầu đồng thời mà không phải chờ hoạt động I/O hoàn tất.

Bảng so sánh 

Để hiểu rõ hơn FastHTML so với các framework phổ biến, bảng dưới đây nêu bật khác biệt chính về thời gian thiết lập, hiệu quả mã và đặc tính hiệu năng giữa FastHTML, Flask và Django.

Tính năng

FastHTML

Flask

Django

Thời gian thiết lập

Tối thiểu: pip install, định nghĩa route và thành phần trong một tệp, gọi serve()

Vừa phải: khởi đầu nhanh với một tệp, nhưng cần template Jinja và thiết lập thư mục static

Dài: yêu cầu scaffold dự án, cấu hình settings, định nghĩa app và nhiều tệp

Engine template

Không cần—dùng đối tượng Python cho HTML

Cần engine Jinja2 cho view

Dùng Django Templates với ngôn ngữ template riêng và thư mục riêng

Tương tác front-end

Khai báo qua HTMX, không cần JavaScript

Thường cần JavaScript thủ công cho tương tác

Cần JavaScript cho tương tác, thường liên quan công cụ bên ngoài

Hiệu quả mã

Cao: ít boilerplate, HTML Pythonic, thống nhất logic + UI

Vừa: routing ngắn gọn nhưng HTML nằm trong template, tương tác cần JS tùy chỉnh

Thấp: logic, template và cấu hình rải rác nhiều tệp

Hiệu năng (Đồng thời)

Cao: xây trên ASGI với hỗ trợ async, phù hợp đồng thời cao

Thấp hơn: dựa trên WSGI, xử lý đồng bộ trừ khi mở rộng với tính năng async

Thấp hơn: dựa trên WSGI và mặc định đồng bộ; cần thiết lập bổ sung để hỗ trợ async

Số dòng mã cho "Hello, World"

Rất ít dòng trong một tệp

Ít dòng, nhưng cần template hoặc HTML inline

Nhiều tệp gồm views, URLs, template và settings

Kết luận

FastHTML mang đến một cách tiếp cận Pythonic mới mẻ để xây dựng ứng dụng web, kết hợp tính linh hoạt của đối tượng Python với sức mạnh thực thi bất đồng bộ. Bằng cách loại bỏ nhu cầu về tệp template riêng, pipeline tài nguyên tĩnh và framework frontend, FastHTML giúp đơn giản hóa phát triển và cho phép bạn xây dựng giao diện động, tương tác nhanh chóng và hiệu quả.

Với HTMX cho tương tác, ASGI cho hiệu năng và tích hợp mượt mà với ORM hỗ trợ async, FastHTML rất phù hợp cho các dự án web hiện đại—từ nền tảng thương mại điện tử đến bảng điều khiển dữ liệu và hơn thế nữa. Thiết lập tối giản, ít boilerplate và codebase thống nhất khiến nó trở thành lựa chọn hấp dẫn cho lập trình viên tìm kiếm giải pháp nhẹ, hiệu quả thay thế cho các framework truyền thống như Django và Flask.

Đối với độc giả quan tâm khám phá các công cụ và cách tiếp cận liên quan đến phát triển web bằng Python, các tài nguyên sau là bước tiếp theo hữu ích.

Python FastHTML FAQs

FastHTML khác Django hoặc Flask như thế nào?

FastHTML loại bỏ nhu cầu về tệp template riêng, cấu hình tài nguyên tĩnh và framework frontend. Nó tập trung vào phát triển chỉ với Python, dùng HTMX cho tính tương tác.

Tôi có thể dùng FastHTML cho ứng dụng quy mô lớn không?

Có. Kiến trúc của FastHTML (Python + HTMX + ASGI) mở rộng tốt cho các ứng dụng hiện đại, hiệu năng cao. Với dự án lớn, bạn có thể mô-đun hóa codebase bằng các thành phần tái sử dụng.

FastHTML có hỗ trợ tính tương tác động như AJAX không?

Có. FastHTML dùng HTMX để xử lý tương tác theo cách khai báo, cho phép cập nhật một phần trang (tương tự AJAX) mà không cần JavaScript tùy chỉnh.

Tôi có thể triển khai ứng dụng FastHTML lên đám mây không?

Chắc chắn. Ứng dụng FastHTML có thể triển khai trên bất kỳ nền tảng nào hỗ trợ ASGI và Python, bao gồm các dịch vụ như Vercel, Fly.io và DigitalOcean.

Mark Pedigo

Tác giả

Mark Pedigo

Mark Pedigo, PhD, là một nhà khoa học dữ liệu xuất sắc với chuyên môn về khoa học dữ liệu trong y tế, lập trình và giáo dục. Với bằng Tiến sĩ Toán học, Cử nhân Khoa học Máy tính và Chứng chỉ Chuyên nghiệp về AI, Mark kết hợp hiểu biết kỹ thuật với khả năng giải quyết vấn đề thực tiễn. Sự nghiệp của anh bao gồm các vai trò trong phát hiện gian lận, dự đoán tử vong ở trẻ sơ sinh và dự báo tài chính, cùng với những đóng góp cho phần mềm ước tính chi phí của NASA. Là một nhà giáo dục, anh đã giảng dạy tại DataCamp và Đại học Washington ở St. Louis, đồng thời cố vấn cho các lập trình viên trẻ. Trong thời gian rảnh, Mark thích hoạt động ngoài trời ở Minnesota cùng vợ là Mandy và chú chó Harley, và chơi piano jazz.

Chủ đề

Liên quan