Phân biệt View trong Django: Hàm so với Lớp

Trong Django, cách triển khai logic xử lý yêu cầu HTTP được chia thành hai mô hình chính: Function-Based Views (FBV)Class-Based Views (CBV). Sự lựa chọn giữa hai kiểu này ảnh hưởng trực tiếp đến khả năng tái sử dụng, mở rộng và bảo trì mã nguồn.

View là gì?

Một view là một thành phần nhận vào một đối tượng HttpRequest và trả về một đối tượng HttpResponse. Đây có thể là một hàm Python (FBV) hoặc một lớp kế thừa từ django.views.View (CBV). Tất cả các view đều được định nghĩa trong tệp views.py của ứng dụng.

Ví dụ đơn giản trả về thời gian hiện tại dưới dạng HTML:

from django.http import HttpResponse
import datetime

def show_timestamp(request):
    current = datetime.datetime.now()
    content = f"<html><body>Thời điểm hiện tại: {current}</body></html>"
    return HttpResponse(content)

Function-Based Views (FBV)

FBV là hàm Python chuẩn, nhận tham số đầu tiên là request, thực hiện xử lý và trả về phản hồi. Cấu trúc rõ ràng, dễ hiểu cho các tác vụ đơn giản.

Ví dụ xử lý cả GET và POST trong một hàm:

from django.shortcuts import render, redirect
from app01.models import Product

def create_product(request):
    if request.method == "POST":
        name = request.POST.get("product_name")
        price = request.POST.get("price")
        Product.objects.create(name=name, price=price)
        return redirect("product_list")
    return render(request, "create_product.html")

Đăng ký trong urls.py:

from django.urls import path
from app01 import views

urlpatterns = [
    path("product/new/", views.create_product),
]

Class-Based Views (CBV)

CBV tổ chức logic theo phương thức tương ứng với HTTP method (GET, POST, PUT…), giúp phân tách trách nhiệm rõ ràng hơn. Lớp phải kế thừa từ View và triển khai các phương thức như get(), post(), v.v.

Ví dụ minh họa:

from django.views import View
from django.shortcuts import render, redirect
from app01.models import Category

class CreateCategory(View):
    def get(self, request):
        return render(request, "create_category.html")

    def post(self, request):
        title = request.POST.get("title")
        Category.objects.create(title=title)
        return redirect("category_index")

Đăng ký URL với cú pháp đặc biệt — gọi phương thức tĩnh as_view():

urlpatterns = [
    path("category/add/", views.CreateCategory.as_view()),
]

Cơ chế hoạt động của CBV

Khi một yêu cầu đến đường dẫn được ánh xạ tới CBV, Django thực hiện tuần tự:

  1. Gọi CreateCategory.as_view() → trả về một hàm view bao bọc.
  2. Hàm view khởi tạo instance lớp (self), gán self.request = request.
  3. Gọi self.dispatch(request, *args, **kwargs) — đây là cổng trung tâm.
  4. dispatch kiểm tra request.method có nằm trong self.http_method_names hay không.
  5. Nếu hợp lệ, dùng getattr(self, method_name) để lấy phương thức tương ứng (ví dụ self.post) và thực thi.
  6. Nếu không hợp lệ, gọi self.http_method_not_allowed().

Giá trị mặc định của http_method_names gồm: ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']. Bạn có thể ghi đè để giới hạn phương thức hỗ trợ:

class ReadOnlyView(View):
    http_method_names = ['get', 'head']
    
    def get(self, request):
        return render(request, "read_only.html")

Áp dụng decorator vào FBV và CBV

Decorator trong FBV được áp dụng trực tiếp như thông thường:

import time
from functools import wraps

def measure_time(func):
    @wraps(func)
    def wrapper(request, *args, **kwargs):
        start = time.time()
        response = func(request, *args, **kwargs)
        print(f"[{func.__name__}] Thời gian thực thi: {time.time() - start:.4f}s")
        return response
    return wrapper

@measure_time
def dashboard(request):
    return render(request, "dashboard.html")

Với CBV, cần chuyển đổi decorator sang dạng áp dụng cho phương thức bằng method_decorator:

  • Áp dụng trên từng phương thức:
from django.utils.decorators import method_decorator

@method_decorator(measure_time, name="get")
class StatsView(View):
    def get(self, request):
        return render(request, "stats.html")
  • Áp dụng trên dispatch để bao phủ toàn bộ phương thức:
class AuthView(View):
    @method_decorator(measure_time)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

    def get(self, request):
        return render(request, "login.html")

    def post(self, request):
        # xử lý đăng nhập
        return redirect("home")
  • Áp dụng trên toàn lớp với nhiều phương thức:
@method_decorator(measure_time, name="get")
@method_decorator(measure_time, name="post")
class ContactView(View):
    def get(self, request):
        return render(request, "contact_form.html")

    def post(self, request):
        # lưu form
        return redirect("contact_success")

Thẻ: Django python web-development cbv fbv

Đăng vào ngày 3 tháng 7 lúc 20:50