Học Django trong 14 ngày - Ngày 2: Mô hình và Cơ sở dữ liệu

By JoeVu, at: 08:58 Ngày 15 tháng 6 năm 2023

Thời gian đọc ước tính: __READING_TIME__ minutes

Learn Django in 14 days - Day 2: Models and Databases
Learn Django in 14 days - Day 2: Models and Databases

Models trong Django được sử dụng để định nghĩa cấu trúc và hành vi của dữ liệu được lưu trữ trong cơ sở dữ liệu. Hiểu cách làm việc với models là điều cần thiết để xây dựng các ứng dụng web mạnh mẽ và có khả năng mở rộng. Vì vậy, hãy cùng tìm hiểu về thế giới của Django models!

Mã nguồn mẫu được thêm vào ở đây 
 

1. Giới thiệu về cơ sở dữ liệu và models trong Django

Hỗ trợ cơ sở dữ liệu của Django dựa trên lớp ánh xạ đối tượng-quan hệ (ORM) mạnh mẽ của nó. ORM tách biệt các phức tạp khi tương tác với các hệ quản trị cơ sở dữ liệu (DBMS) khác nhau và cho phép các nhà phát triển làm việc với cơ sở dữ liệu bằng mã Python thay vì viết các truy vấn SQL thô (điều này KHÔNG được khuyến nghị dù bằng cách nào).

Django hỗ trợ nhiều cơ sở dữ liệu quan hệ khác nhau, bao gồm PostgreSQL, MySQL, SQLite và Oracle, cùng nhiều loại khác. Tính linh hoạt này cho phép các nhà phát triển lựa chọn backend cơ sở dữ liệu phù hợp nhất với yêu cầu của dự án. Cơ sở dữ liệu Django được khuyến nghị là PostgreSQL.

Trong đó, một model cơ sở dữ liệu model là một lớp Python đại diện cho một bảng cơ sở dữ liệu. Nó định nghĩa các trườngphương thức để tương tác với cơ sở dữ liệu bên dưới. Django models cung cấp một cách tiếp cận cấp cao và trực quan để làm việc với cơ sở dữ liệu, giúp dễ dàng quản lý và thao tác dữ liệu hơn.

django model

Sau đó, chúng ta sẽ thảo luận về một số chủ đề nâng cao với các gói bổ sung và hữu ích

  1. Các trường
  2. Models
  3. Cấu hình cơ sở dữ liệu


2. Tạo một model Django

Để tạo một model Django, bạn cần định nghĩa một lớp Python kế thừa từ lớp cơ sở django.db.models.Model. Lớp này đại diện cho một bảng trong cơ sở dữ liệu. Mỗi thuộc tính của lớp đại diện cho một trường trong bảng.


Định nghĩa các trường

Các trường định nghĩa loại dữ liệu có thể được lưu trữ trong cơ sở dữ liệu. Django cung cấp nhiều loại trường khác nhau như CharField, IntegerField, DateField, ForeignKey và nhiều loại khác nữa. Bạn có thể chọn loại trường phù hợp dựa trên dữ liệu bạn muốn lưu trữ.


Các loại trường

Django cung cấp một loạt các loại trường để xử lý các loại dữ liệu khác nhau. Ví dụ: CharField được sử dụng để lưu trữ văn bản, IntegerField để lưu trữ số nguyên, DateField để lưu trữ ngày tháng, v.v. Việc chọn loại trường chính xác đảm bảo tính toàn vẹn dữ liệu và khả năng lưu trữ hiệu quả.


Các tùy chọn trường

Các trường có thể có thêm tùy chọn để tùy chỉnh hành vi của chúng. Một số tùy chọn phổ biến bao gồm null để chỉ định xem một trường có thể trống hay không, default để cung cấp một giá trị mặc định cho trường, unique để đảm bảo tính duy nhất và nhiều tùy chọn khác nữa. Các tùy chọn này cho phép bạn tinh chỉnh hành vi của models.

Một ví dụ về model được định nghĩa như bên dưới

from django.contrib.postgres.fields import ArrayField
from django.db import models


class Book(models.Model):
    author = models.ForeignKey(
        "Author",
        on_delete=models.CASCADE,
        related_name="jobs",
    )
    tags = ArrayField(
        models.CharField(max_length=256, null=True, blank=True),
        blank=True,
        null=True,
    )
    description = models.TextField()
    title = models.CharField(max_length=256, null=True, blank=True)
    category = models.CharField(max_length=256, null=True, blank=True)
    price = models.DecimalField(max_digits=None, decimal_places=None)
    
    def is_comic(self):
        return "comic" in self.category.lower()

 

3. Di chuyển cơ sở dữ liệu (Database migrations)

Khi bạn thực hiện các thay đổi đối với models, chẳng hạn như thêm hoặc sửa đổi các trường, Django cung cấp một hệ thống di chuyển để quản lý các thay đổi này trong schema cơ sở dữ liệu.


Tạo các di chuyển

Hệ thống di chuyển của Django cho phép bạn tự động tạo các câu lệnh SQL cần thiết để áp dụng các thay đổi model của bạn. Bạn có thể sử dụng lệnh makemigrations để tạo các tệp di chuyển dựa trên các thay đổi được phát hiện trong models của bạn.

python manage.py makemigrations app
python manage.py makemigrations

 

django model


Áp dụng các di chuyển

Sau khi bạn có các tệp di chuyển, bạn có thể áp dụng chúng vào cơ sở dữ liệu bằng lệnh migrate. Điều này sẽ cập nhật schema cơ sở dữ liệu sao cho khớp với trạng thái hiện tại của models. Django theo dõi các di chuyển đã được áp dụng trong bảng django_migrations trong cơ sở dữ liệu hiện tại, giúp dễ dàng quản lý các cập nhật schema.

python manage.py migrate <app> <migration_number>

django model


Hoàn tác và khôi phục

Django cũng hỗ trợ hoàn táckhôi phục các di chuyển. Nếu bạn gặp sự cố sau khi áp dụng một di chuyển, bạn có thể hoàn tác nó để khôi phục trạng thái trước đó. Ngoài ra, bạn có thể khôi phục một tập hợp các di chuyển để quay lại một thời điểm cụ thể.

python manage.py migrate <app> <migration_number>
python manage.py migrate bookstore 0001
python manage.py migrate bookstore zero  # Hoàn tác về số 0



Các di chuyển giả lập (Fake migrations)

Đây là một tính năng quan trọng khi có một số xung đột giữa các cập nhật cơ sở dữ liệu thực tế và số di chuyển được lưu trữ trong bảng django_migrations. Hãy tưởng tượng một trường hợp khi bạn đã thực hiện các thay đổi trong cơ sở dữ liệu do yêu cầu khẩn cấp từ khách hàng, nhưng bạn chưa tạo tập lệnh di chuyển và áp dụng nó vào cơ sở dữ liệu. Đây là lúc --fake migration được sử dụng.

python manage.py migrate bookstore 0002 --fake  # số di chuyển hiện tại là 0001, sau thay đổi này, nó sẽ là 0002 mà không cần thực hiện di chuyển thực tế.


Ưu điểm

  1. Sự tiến hóa của Schema cơ sở dữ liệu: Điều này cung cấp sự tiến hóa liền mạch và được kiểm soát của schema cơ sở dữ liệu theo thời gian. Nó đơn giản hóa quá trình thực hiện các thay đổi đối với cấu trúc cơ sở dữ liệu mà không cần các tập lệnh SQL thủ công hoặc tạo lại toàn bộ cơ sở dữ liệu.

  2. Kiểm soát phiên bản: Các di chuyển được lưu trữ dưới dạng các tệp có phiên bản trong codebase của dự án, giúp dễ dàng theo dõi và quản lý các thay đổi đối với schema cơ sở dữ liệu cùng với mã nguồn của ứng dụng. Điều này tạo điều kiện thuận lợi cho việc cộng tác, đánh giá code và hoàn tác nếu cần.

  3. Di chuyển dữ liệu: Ngoài các thay đổi về cấu trúc, các di chuyển Django hỗ trợ di chuyển dữ liệu. Điều này cho phép bạn viết mã Python để di chuyển và biến đổi dữ liệu khi thực hiện các thay đổi schema, đảm bảo tính toàn vẹn dữ liệu trong quá trình di chuyển.

  4. Quản lý phụ thuộc: Các di chuyển hỗ trợ các phụ thuộc giữa các tệp di chuyển khác nhau. Điều này có nghĩa là bạn có thể xác định thứ tự áp dụng các di chuyển, xử lý các trường hợp phức tạp khi một di chuyển phụ thuộc vào việc hoàn thành một di chuyển khác.

  5. Hoàn tác và khôi phục: Điều này cho phép bạn thực hiện/hoàn tác các thay đổi đối với schema cơ sở dữ liệu. Điều này có thể hữu ích trong trường hợp một di chuyển gây ra sự cố hoặc khi bạn cần quay lại trạng thái trước đó.

Nhược điểm

  1. Các di chuyển phức tạp: Trong một số trường hợp, đặc biệt là khi xử lý các thay đổi cơ sở dữ liệu phức tạp, việc viết và quản lý các di chuyển có thể trở nên khó khăn. Xử lý các trường hợp đặc biệt, chẳng hạn như đổi tên hoặc thay đổi các trường hiện có, có thể yêu cầu can thiệp thủ công hoặc các tập lệnh di chuyển tùy chỉnh. Một số di chuyển tùy chỉnh có thể bị hỏng sau vài năm do nhiều cập nhật ràng buộc cơ sở dữ liệu.

  2. Ảnh hưởng đến hiệu suất: Các di chuyển có thể ảnh hưởng đến hiệu suất ứng dụng trong quá trình di chuyển, đặc biệt là khi xử lý các tập dữ liệu lớn. Việc áp dụng các di chuyển phức tạp hoặc di chuyển một lượng lớn dữ liệu có thể yêu cầu xem xét kỹ lưỡng và tối ưu hóa để giảm thiểu thời gian chết và suy giảm hiệu suất. Có một mẹo để tránh điều đó bằng cách di chuyển hiệu suất trong các tác vụ nền (Celery + Redis)

  3. Tương tác với dữ liệu hiện có: Di chuyển dữ liệu hiện có có thể khó khăn, đặc biệt là khi xử lý các biến đổi dữ liệu hoặc di chuyển dữ liệu yêu cầu logic phức tạp. Việc đảm bảo tính toàn vẹn và nhất quán dữ liệu trong quá trình di chuyển có thể yêu cầu lập kế hoạch và thử nghiệm cẩn thận.

  4. Phụ thuộc bên ngoài: Các di chuyển có thể dựa trên các phụ thuộc hoặc yếu tố bên ngoài bên ngoài hệ thống di chuyển. Các thay đổi đối với các hệ thống bên ngoài, chẳng hạn như máy chủ cơ sở dữ liệu hoặc thư viện, đôi khi có thể gây ra các vấn đề về khả năng tương thích và yêu cầu thêm nỗ lực để giải quyết.


4. Truy vấn cơ sở dữ liệu

Django cung cấp một ORM mạnh mẽ (Ánh xạ đối tượng-quan hệ) cho phép bạn truy vấn cơ sở dữ liệu bằng mã Python. ORM tách biệt engine cơ sở dữ liệu cơ bản, giúp dễ dàng viết các truy vấn cơ sở dữ liệu theo cách không phụ thuộc vào cơ sở dữ liệu.


Các truy vấn cơ bản

Bạn có thể truy xuất các đối tượng từ cơ sở dữ liệu bằng thuộc tính objects của một lớp model. Ví dụ: MyModel.objects.all() trả về tất cả các đối tượng của lớp MyModel. Bạn cũng có thể lọc các đối tượng dựa trên các tiêu chí cụ thể bằng phương thức filter().

Book.objects.filter(author_id__in=[1, 2, 3])  # Điều này trả về tất cả các sách có id tác giả là 1,2,3
Book.objects.filter(author__name__contains="Joe", category__icontains="comic")  # Điều này trả về tất cả các sách có tên tác giả chứa "Joe" và thể loại chứa "comic" không phân biệt chữ hoa chữ thường.



Lọc và sắp xếp

Django cung cấp nhiều phương thức để lọc và sắp xếp kết quả truy vấn. Bạn có thể sử dụng các phương thức như filter(), exclude()order_by() để thu hẹp kết quả và chỉ định thứ tự mong muốn.

Book.objects.filter(author__name__contains="Joe", category__icontains="comic").exclude(author__name__contains="Vu").order_by("-id")  # Điều này trả về tất cả các sách có tên tác giả chứa "Joe" và thể loại chứa "comic" không phân biệt chữ hoa chữ thường, nhưng loại trừ những cuốn sách có tên tác giả chứa "Vu" phân biệt chữ hoa chữ thường. Danh sách trả về được sắp xếp theo "ID" giảm dần.



Tổng hợp và chú thích

ORM của Django cũng hỗ trợ tổng hợp và chú thích để thực hiện các phép tính và tổng hợp trên kết quả truy vấn. Bạn có thể sử dụng các phương thức như count(), sum(), avg()annotate() để truy xuất dữ liệu tổng hợp từ cơ sở dữ liệu.

Book.objects.aggregate(count=Count("id"))
Book.objects.aggregate(total_price=Sum("price"))


5. Mối quan hệ giữa các models

Django cho phép bạn định nghĩa các mối quan hệ giữa các models, cho phép bạn thiết lập các kết nối và liên kết giữa các thực thể khác nhau trong ứng dụng của bạn.


Mối quan hệ một-một

Mối quan hệ một-một là một loại mối quan hệ phổ biến, trong đó mỗi bản ghi trong một model được liên kết với chính xác một bản ghi trong một model khác. Bạn có thể định nghĩa mối quan hệ một-một bằng cách sử dụng kiểu trường OneToOneField.


Mối quan hệ một-nhiều

Mối quan hệ một-nhiều thể hiện mối quan hệ mà một bản ghi trong một model có thể được liên kết với nhiều bản ghi trong một model khác. Điều này được thực hiện bằng cách sử dụng kiểu trường ForeignKey.


Mối quan hệ nhiều-nhiều

Mối quan hệ nhiều-nhiều là một mối quan hệ phức tạp hơn, trong đó nhiều bản ghi trong một model có thể được liên kết với nhiều bản ghi trong một model khác. Django cung cấp kiểu trường ManyToManyField để xử lý loại mối quan hệ này.


6. Kế thừa model

Django hỗ trợ kế thừa model, cho phép bạn tạo các model chuyên biệt hơn dựa trên các model hiện có.


Các lớp cơ sở trừu tượng

Bạn có thể định nghĩa một lớp cơ sở trừu tượng làm lớp cha cho các model khác. Các lớp cơ sở trừu tượng chỉ được sử dụng cho mục đích kế thừa và không được tạo thành các bảng riêng biệt trong cơ sở dữ liệu.

from django.db import models


class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

    @property
    def added(self):
        return self.created_at

    @property
    def updated(self):
        return self.updated_at

    @property
    def created_by(self):
        if hasattr(self, "added_by"):
            return self.added_by
        return None

 



Kế thừa đa bảng

Với kế thừa đa bảng, mỗi model trong phân cấp kế thừa được lưu trữ dưới dạng một bảng riêng biệt trong cơ sở dữ liệu. Django tự động tạo các mối quan hệ giữa các bảng này để duy trì cấu trúc kế thừa.


Các model proxy

Các model proxy là một dạng kế thừa model khác, trong đó bạn có thể tạo một model proxy hoạt động giống như model gốc nhưng với một số sửa đổi. Các model proxy rất hữu ích để thêm các phương thức bổ sung hoặc thay đổi hành vi mặc định của một model.

from django.contrib.postgres.fields import ArrayField
from django.db import models


class Book(models.Model):
    author = models.ForeignKey(
        "Author",
        on_delete=models.CASCADE,
        related_name="jobs",
    )
    tags = ArrayField(
        models.CharField(max_length=256, null=True, blank=True),
        blank=True,
        null=True,
    )
    description = models.TextField()
    title = models.CharField(max_length=256, null=True, blank=True)
    category = models.CharField(max_length=256, null=True, blank=True)
    price = models.DecimalField(max_digits=None, decimal_places=None)
    
    def is_comic(self):
        return "comic" in self.category.lower()


class KidBook(Book):
    class Meta:
        proxy = True

    def for_kid(self):
        return True


7. Các thực hành tốt nhất cho Django models

  1. Quy ước đặt tên

    • Sử dụng danh từ số ít cho tên lớp model và làm cho chúng mô tả và trực quan.
    • Sử dụng chữ thường và dấu gạch dưới cho tên trường.
    • Cân nhắc sử dụng tên rõ ràng và có ý nghĩa cho các trường để cải thiện khả năng đọc code.
  2. Các loại trường và ràng buộc

    • Chọn các loại trường phù hợp thể hiện chính xác dữ liệu đang được lưu trữ.
    • Thêm các ràng buộc như null=True, blank=Trueunique=True để đảm bảo tính toàn vẹn dữ liệu.
    • Sử dụng ForeignKeyManyToManyField để thiết lập mối quan hệ giữa các models.
  3. Chỉ mục

    • Xác định các trường thường được sử dụng để lọc hoặc tìm kiếm và cân nhắc thêm chỉ mục cơ sở dữ liệu để cải thiện hiệu suất truy vấn.
    • Sử dụng tùy chọn db_index=True của Django cho các trường thường được sử dụng trong truy vấn.
  4. Phương thức và thuộc tính model

    • Định nghĩa các phương thức trên models để đóng gói logic nghiệp vụ hoặc thực hiện các thao tác phức tạp liên quan đến dữ liệu của model.
    • Sử dụng các thuộc tính để tính toán các giá trị dẫn xuất hoặc cung cấp quyền truy cập thuận tiện vào dữ liệu liên quan.
  5. Tùy chọn Meta

    • Sử dụng lớp Meta của Django để cung cấp các tùy chọn và siêu dữ liệu bổ sung cho models.
    • Chỉ định thứ tự của kết quả truy vấn bằng thuộc tính ordering.
    • Định nghĩa các ràng buộc duy nhất bằng unique_together để thực thi các kết hợp trường duy nhất.
  6. Sử dụng Migrations

    • Sử dụng hệ thống di chuyển của Django để quản lý các thay đổi đối với schema cơ sở dữ liệu theo thời gian.
    • Tạo và áp dụng các di chuyển bất cứ khi nào có thay đổi đối với models hoặc schema cơ sở dữ liệu.
  7. Kiểm thử

    • Viết các bài kiểm tra đơn vị cho models để đảm bảo hành vi và tương tác của chúng là chính xác.
    • Kiểm tra các phương thức, thuộc tính và mối quan hệ của model để xác minh chức năng của chúng.
  8. Tổ chức code

    • Tổ chức các models thành các mô-đun hoặc tệp riêng biệt dựa trên chức năng hoặc miền liên quan.
    • Cân nhắc sử dụng cấu trúc ứng dụng của Django để nhóm các models một cách logic.
  9. Tài liệu

    • Thêm nhận xét và docstrings vào models, trường và phương thức để cung cấp tính rõ ràng và làm cho code dễ hiểu hơn.
    • Tài liệu hóa bất kỳ giả định, ràng buộc hoặc cân nhắc đặc biệt nào liên quan đến thiết kế hoặc việc sử dụng model.
  10. Tối ưu hóa hiệu suất

    • Sử dụng các phương thức select_relatedprefetch_related của Django để giảm thiểu số lượng truy vấn cơ sở dữ liệu và tối ưu hóa việc truy xuất dữ liệu liên quan.
    • Lưu ý về các truy vấn cơ sở dữ liệu khi làm việc với các tập dữ liệu lớn và cân nhắc sử dụng phân trang hoặc các chiến lược khác để giới hạn kết quả truy vấn.
  11. Model nên lớn

    • Lớp Model nên lớn, phức tạp để các phương thức của nó có thể được gọi ở nhiều nơi khác nhau, cải thiện code sạch và code có thể tái sử dụng
  12. Mẹo

    • Sử dụng cached_property khi bạn muốn tiết kiệm tài nguyên tính toán
    • Sử dụng Django Signal hoặc ghi đè save nếu có thể để cải thiện các ứng dụng tách rời


8. Các chủ đề nâng cao


8.1 Signal

Django Signal cho phép các thành phần khác nhau của một ứng dụng Django gửi và nhận thông báo về các sự kiện cụ thể, cho phép ghép nối lỏng lẻo và thúc đẩy tính mô đun bằng cách tạo điều kiện thuận lợi cho việc giao tiếp giữa các phần ứng dụng mà không có sự phụ thuộc trực tiếp. Cơ chế mạnh mẽ này có thể được sử dụng để mở rộng chức năng, tích hợp với các ứng dụng của bên thứ ba và thực hiện các tác vụ không đồng bộ, làm cho Django Signals trở thành một công cụ có giá trị cho các nhà phát triển.

Tuy nhiên, điều này cũng có nghĩa là làm tăng độ phức tạp của ứng dụng, hãy lưu ý điều đó.

Ưu điểm

  1. Ghép nối lỏng lẻo: Signal cho phép code mô đun và dễ bảo trì bằng cách tách rời các thành phần ứng dụng.
  2. Khả năng mở rộng: Các tín hiệu và bộ thu tùy chỉnh tạo điều kiện thuận lợi cho việc thêm chức năng mới một cách dễ dàng.
  3. Thực thi không đồng bộ: Tính năng này hỗ trợ xử lý nền để cải thiện hiệu suất.
  4. Tích hợp với các ứng dụng của bên thứ ba: Tính năng này cho phép tích hợp liền mạch với các thành phần bên ngoài.

Nhược điểm

  1. Độ phức tạp: Signals có thể làm cho codebase khó hiểu hơn và theo dõi các tương tác.
  2. Thiếu tính rõ ràng: Việc giao tiếp giữa các thành phần không rõ ràng trong code.
  3. Ảnh hưởng tiềm tàng đến hiệu suất: Xử lý một số lượng lớn tín hiệu và bộ thu có thể gây ra chi phí.
Tag list:
- Django
- Tips
- Django Migration
- Django best practices
- Django Examples
- Django Field Options
- Django Queryset
- Django Manager
- Django model
- Django Query
- Django Database
- Django Field
- override save
- signal

Liên quan

Django Python

Đọc thêm
Django Learning

Đọc thêm

Theo dõi

Theo dõi bản tin của chúng tôi và không bao giờ bỏ lỡ những tin tức mới nhất.