Django: Xử lý Request và Response trong ứng dụng Web

Xử lý Request và Response trong Django


Mục lục- Tổng quan về Request và Response

  • Đối tượng HttpRequest
  • Các thuộc tính quan trọng của Request
  • Minh họa tải file lên server
  • Đối tượng HttpResponse
  • Đối tượng JsonResponse
  • Các hàm tiện ích của Django
  • Hàm render() và các tham số
  • Hàm redirect() và các tham số
  • Tìm hiểu thêm

Đối tượng HttpRequest

Khi một trang web được yêu cầu, Django tự động tạo một đối tượng HttpRequest chứa toàn bộ thông tin gốc của request đó. Django sau đó truyền tự động đối tượng này đến view function tương ứng, và theo quy ước, view function sử dụng tham số request để nhận đối tượng này.

Các giá trị thường dùng liên quan đến Request

  • request.path_info - Trả về URL mà người dùng truy cập, không bao gồm domain và port (ví dụ: /trang-chu/)
  • request.path - Tương tự như path_info
  • request.method - Phương thức HTTP được sử dụng (dạng chuỗi viết hoa, 8 loại)
  • request.GET - Đối tượng giống dictionary chứa tất cả tham số GET (tham số trên URL)
  • request.POST - Đối tượng giống dictionary chứa tất cả tham số POST (dữ liệu form gửi đi)
  • request.body - Nội dung request dạng byte, dữ liệu trong POST được trích xuất từ đây

Các thuộc tính của HttpRequest

Tất cả các thuộc tính dưới đây được coi là chỉ đọc (read-only), trừ khi có ghi chú khác.

"""
Django đóng gói các thông tin từ request header thành các thuộc tính trong đối tượng HttpRequest.
Ngoại trừ một số trường hợp đặc biệt, các thuộc tính đều là chỉ đọc.
"""

0.HttpRequest.scheme
   Chuỗi biểu diễn scheme của request (thường là http hoặc https)

1.HttpRequest.body
   Một chuỗi đại diện cho phần thân của request. Rất hữu ích khi xử lý các request
   không phải dạng HTTP như hình ảnh nhị phân, XML, JSON.
   
   Tuy nhiên, khi cần xử lý dữ liệu form, nên sử dụng HttpRequest.POST.
   
   Có thể thao tác với body bằng các phương thức tương tự file trong Python
   (xem HttpRequest.read()).

2.HttpRequest.path
   Chuỗi biểu diễn thành phần đường dẫn của request (không có domain).
   Ví dụ: "/san-pham/dien-thoai-iphone-15/"

3.HttpRequest.method
   Chuỗi biểu diễn phương thức HTTP được sử dụng. Phải viết hoa.
   Ví dụ: "GET", "POST", "PUT", "DELETE"

4.HttpRequest.encoding
   Chuỗi biểu diễn mã hóa của dữ liệu gửi đến (nếu là None sẽ sử dụng DEFAULT_CHARSET,
   mặc định là 'utf-8'). Thuộc tính này có thể ghi, cho phép thay đổi mã hóa
   khi đọc dữ liệu từ GET hoặc POST.

5.HttpRequest.GET 
   Đối tượng giống dictionary chứa tất cả tham số HTTP GET.

6.HttpRequest.POST
   Đối tượng giống dictionary, chứa dữ liệu form nếu request có表单数据.
   Lưu ý: POST request có thể có dictionary rỗng - nếu gửi form không có dữ liệu,
   QueryDict vẫn được tạo. Vì vậy nên dùng if request.method == "POST" 
   thay vì if request.POST để kiểm tra phương thức.
   
   Nếu dùng POST để tải file, thông tin file nằm trong thuộc tính FILES.

7.HttpRequest.COOKIES
   Dictionary chuẩn Python chứa tất cả cookie, key và value đều là chuỗi.

8.HttpRequest.FILES
   Đối tượng giống dictionary chứa thông tin các file được tải lên.
   Mỗi key trong FILES tương ứng với thuộc tính name của input type="file".
   
   Lưu ý: FILES chỉ chứa dữ liệu khi method là POST và form có 
   enctype="multipart/form-data". Ngược lại, FILES là dictionary rỗng.

9.HttpRequest.META
   Dictionary chứa tất cả HTTP header. Một số header quan trọng:

   CONTENT_LENGTH - Độ dài request body (dạng chuỗi)
   CONTENT_TYPE - MIME type của request body
   HTTP_ACCEPT - Các loại content mà client chấp nhận
   HTTP_ACCEPT_ENCODING - Các loại encoding được chấp nhận
   HTTP_ACCEPT_LANGUAGE - Ngôn ngữ được chấp nhận
   HTTP_HOST - Host header từ client
   HTTP_REFERER - Trang referrer
   HTTP_USER_AGENT - Chuỗi user-agent của client
   QUERY_STRING - Chuỗi query chưa được parse
   REMOTE_ADDR - Địa chỉ IP của client
   REMOTE_HOST - Hostname của client
   REMOTE_USER - User đã được xác thực
   REQUEST_METHOD - Phương thức request
   SERVER_NAME - Hostname của server
   SERVER_PORT - Cổng của server

10.HttpRequest.user
   Đối tượng kiểu AUTH_USER_MODEL biểu diễn user hiện tại đã đăng nhập.
   
   Nếu user chưa đăng nhập, user sẽ là instance của 
   django.contrib.auth.models.AnonymousUser. Dùng is_authenticated() để phân biệt:

   if request.user.is_authenticated():
       # Xử lý cho user đã đăng nhập
   else:
       # Xử lý cho user chưa đăng nhập
   
   Thuộc tính user chỉ khả dụng khi Django enable AuthenticationMiddleware.

11.HttpRequest.session
   Đối tượng dictionary có thể đọc và ghi, biểu diễn session hiện tại.
   Chỉ khả dụng khi Django enable session support.

Minh họa tải file lên server

def handle_upload(request):
    """
    Trước khi lưu file upload, dữ liệu cần được lưu tạm ở đâu đó.
    Mặc định khi file nhỏ hơn 2.5MB, Django đọc toàn bộ nội dung file vào memory.
    Khi file lớn, Django ghi file vào temporary file trong thư mục tạm của hệ thống.
    """
    if request.method == "POST":
        # Lấy tên file từ FILES, "file" là name của input type="file"
        filename = request.FILES["file"].name
        # Tạo file mới trong thư mục dự án
        with open(filename, "wb") as f:
            # Đọc từng phần của file upload
            for chunk in request.FILES["file"].chunks():
                # Ghi vào local file
                f.write(chunk)
        return HttpResponse("Tải lên thành công")
    
# Template HTML
<form action="" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="file" name="tep-tai-len">
    <button>Tải lên</button>
</form>
  • Các phương thức của HttpRequest
1.HttpRequest.get_host()

   Trả về host gốc của request dựa trên HTTP_X_FORWARDED_HOST (nếu USE_X_FORWARDED_HOST=True)
   và HTTP_HOST header. Nếu không có giá trị, sử dụng SERVER_NAME và SERVER_PORT.
   
   Ví dụ: "192.168.1.100:8080"

2.HttpRequest.get_full_path()
   Trả về path kèm query string.
   Ví dụ: "/danh-sach-san-pham?trang=2&sap-xep=gia-tang"

3.HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
   Trả về giá trị cookie đã được ký. Nếu chữ ký không hợp lệ, trả về BadSignature.
   
   Tham số salt cung cấp bảo vệ thêm chống brute-force attack.
   Tham số max_age kiểm tra timestamp để đảm bảo cookie không hết hạn.

4.HttpRequest.is_secure()
   Trả về True nếu request được gửi qua HTTPS.

5.HttpRequest.is_ajax()
   Trả về True nếu request được gửi qua XMLHttpRequest.
   Kiểm tra header HTTP_X_REQUESTED_WITH có giá trị 'XMLHttpRequest'.

Lưu ý: Khi giá trị là danh sách (như checkbox, select multiple), cần dùng: request.POST.getlist("ten_thuoc_tinh")

Đối tượng HttpResponse

Khác với HttpRequest được Django tự động tạo, HttpResponse là trách nhiệm của开发者. Mỗi view cần khởi tạo, điền dữ liệu và trả về HttpResponse.

from django.shortcuts import render, redirect, HttpResponse

HttpResponse('nội dung chuỗi')
render(request, 'đường dẫn template', {context dict})
redirect('địa chỉ chuyển hướng')
# Dự án API - trả về JSON
from django.http.response import JsonResponse

def api_data(request):
    data = {'ho_ten': 'Nguyen Van A', 'tuoi': 25}
    return JsonResponse(data)

JsonResponse(data, safe=False)  # Cho phép serializable list
  • Thiết lập header và content
from django.http import HttpResponse

response = HttpResponse("Nội dung trang web")
response = HttpResponse("Chỉ text", content_type="text/plain")

# Thiết lập hoặc xóa header
response = HttpResponse()
response['Content-Type'] = 'text/html; charset=UTF-8'
del response['Content-Type']
  • Các thuộc tính quan trọng
HttpResponse.content - Nội dung response
HttpResponse.charset - Mã hóa nội dung
HttpResponse.status_code - Mã trạng thái HTTP

Đối tượng JsonResponse

JsonResponse là subclass của HttpResponse, được thiết kế riêng để tạo response dạng JSON.

from django.http import JsonResponse

response = JsonResponse({'ma': 'SP001', 'ten': 'Laptop'})
print(response.content)
# Output: b'{"ma": "SP001", "ten": "Laptop"}'

Mặc định chỉ chấp nhận dictionary. Để trả về list hoặc các kiểu khác:

response = JsonResponse([1, 2, 3], safe=False)

Các hàm tiện ích của Django

Hàm render() và tham số

Kết hợp template với context dictionary và trả về HttpResponse đã được render.

Các tham số:

  • request - Đối tượng request để tạo response
  • template_name - Tên đầy đủ của template
  • context - Dictionary thêm vào template context (mặc định là dict rỗng)
  • content_type - MIME type (mặc định là 'text/html')
  • status - Mã trạng thái (mặc định 200)
  • using - Tên template engine để load template
from django.shortcuts import render

def trang_chu(request):
    return render(request, 'cuahang/index.html', {'san_pham': 'iPhone'})

Tương đương với:

from django.http import HttpResponse
from django.template import loader

def trang_chu(request):
    template = loader.get_template('cuahang/index.html')
    context = {'san_pham': 'iPhone'}
    return HttpResponse(template.render(context, request))

Hàm redirect() và tham số

Tham số có thể là:

  • Một model: Gọi get_absolute_url() của model đó
  • Tên view với tham số: Sử dụng reverse để resolve URL
  • URL tuyệt đối hoặc tương đối: Sử dụng trực tiếp làm điểm đến

Mặc định trả về redirect tạm thời (temporary redirect). Thêm permanent=True để redirect vĩnh viễn.

Các cách sử dụng redirect():

  • Truyền ORM object - Gọi get_absolute_url() để lấy URL:
from django.shortcuts import redirect

def xu_ly(request):
    san_pham = SanPham.objects.get(pk=1)
    return redirect(san_pham)
  • Truyền tên view:
def xu_ly(request):
    return redirect('danh-sach-san-pham', danh_muc='dien-thoai')
  • Truyền URL cụ thể:
def xu_ly(request):
    return redirect('/lien-he/')
  • URL đầy đủ:
def xu_ly(request):
    return redirect('https://vietnam.com/')
  • Redirect vĩnh viễn:
def xu_ly(request):
    san_pham = SanPham.objects.get(pk=1)
    return redirect(san_pham, permanent=True)

Tìm hiểu thêm

Redirect tạm thời (302) và redirect vĩnh viễn (301) trông giống nhau với người dùng,
nhưng khác nhau với search engine bot.

Khi trang A redirect tạm thời đến trang B, search engine sẽ index trang A.
Khi trang A redirect vĩnh viễn đến trang B, search engine sẽ index trang B.
"""

Đăng vào ngày 9 tháng 6 lúc 04:59