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


Mô hình 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 các mô hình 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 thế giới của các mô hình Django!
Mã nguồn mẫu được thêm vào ở đây
1. Giới thiệu về cơ sở dữ liệu và mô hình Django
Hỗ trợ cơ sở dữ liệu của Django dựa trên lớp ánh xạ quan hệ đối tượng (ORM) mạnh mẽ của nó. ORM tách biệt các phức tạp của việc tương tác với các hệ quản trị cơ sở dữ liệu khác nhau (DBMS) 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ưới bất kỳ hình thức 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, trong số những cơ sở dữ liệu 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 mô hình cơ sở dữ liệu là một lớp Python thể hiện một bảng cơ sở dữ liệu. Nó định nghĩa các trường và phương thức để tương tác với cơ sở dữ liệu cơ bản. Các mô hình Django cung cấp một cách làm việc với cơ sở dữ liệu ở mức cao và trực quan, giúp dễ dàng quản lý và thao tác dữ liệu hơn.
Sau đó, chúng ta sẽ thảo luận một số chủ đề nâng cao với các gói bổ sung và hữu ích
- Các trường
- https://github.com/respondcreate/django-versatileimagefield: Một gói ImageField với nhiều tính năng
- https://github.com/romgar/django-dirtyfields: Theo dõi các thay đổi của phiên bản mô hình và các giá trị cơ sở dữ liệu đã lưu hiện tại
- https://github.com/stefanfoulis/django-phonenumber-field: Các trường xác thực số điện thoại Python
- https://github.com/respondcreate/django-versatileimagefield: Một gói ImageField với nhiều tính năng
- Mô hình
- Cấu hình cơ sở dữ liệu
2. Tạo một mô hình Django
Để tạo một mô hình 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 thể hiện một bảng trong cơ sở dữ liệu. Mỗi thuộc tính của lớp thể hiện một trường trong bảng.
Định nghĩa các trường
Các trường xác định 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 đúng loại trường đảm bảo tính toàn vẹn dữ liệu và 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 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 các mô hình.
Một ví dụ về mô hình đượ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
Khi bạn thực hiện các thay đổi đối với mô hình của mình, 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 lược đồ 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 mô hình 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 mô hình của bạn.
python manage.py makemigrations app
python manage.py makemigrations
Á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 lược đồ cơ sở dữ liệu cho phù hợp với trạng thái hiện tại của các mô hình của bạn. Django theo dõi các di chuyển nào đã đượ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 lược đồ.
python manage.py migrate
Hoàn tác và khôi phục
Django cũng hỗ trợ hoàn tác và khô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 điểm thời gian cụ thể.
python manage.py migrate
python manage.py migrate bookstore 0001
python manage.py migrate bookstore zero # Khôi phục lại về zero
Các di chuyển giả
Đâ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
-
Tiến hóa lược đồ cơ sở dữ liệu: Điều này cung cấp một quá trình tiến hóa liền mạch và được kiểm soát của lược đồ 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.
-
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 lược đồ 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, xem xét mã và hoàn tác nếu cần.
-
Di chuyển dữ liệu: Ngoài các thay đổi về cấu trúc, các di chuyển Django còn 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à chuyển đổi dữ liệu khi thực hiện các thay đổi lược đồ, đảm bảo tính toàn vẹn dữ liệu trong quá trình di chuyển.
-
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 mà một di chuyển phụ thuộc vào việc hoàn thành của di chuyển khác.
-
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 lược đồ 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 khôi phục lại trạng thái trước đó.
Nhược điểm
-
Các di chuyển phức tạp: Trong một số trường hợp cụ thể, đặ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 ngoại lệ, 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 sự 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.
-
Ảnh hưởng đến hiệu suất: Các di chuyển có thể ảnh hưởng đến hiệu suất của ứ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)
-
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 chuyể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 của dữ liệu trong quá trình di chuyển có thể yêu cầu lập kế hoạch và kiểm tra cẩn thận.
-
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 chính 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ạ quan hệ đối tượng) cho phép bạn truy vấn cơ sở dữ liệu bằng mã Python. ORM tách biệt bộ máy 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 mô hình. 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 pháp để lọc và sắp xếp kết quả truy vấn. Bạn có thể sử dụng các phương pháp như filter()
, exclude()
và 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 được 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 pháp như count()
, sum()
, avg()
và 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 mô hình
Django cho phép bạn định nghĩa các mối quan hệ giữa các mô hình, 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-đến-một
Mối quan hệ một-đến-một là một loại mối quan hệ phổ biến, trong đó mỗi bản ghi trong một mô hình được liên kết với chính xác một bản ghi trong một mô hình khác. Bạn có thể định nghĩa một mối quan hệ một-đến-một bằng cách sử dụng kiểu trường OneToOneField
.
Mối quan hệ một-đến-nhiều
Mối quan hệ một-đến-nhiều thể hiện một mối quan hệ mà một bản ghi trong một mô hình có thể được liên kết với nhiều bản ghi trong một mô hình 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-đến-nhiều
Mối quan hệ nhiều-đến-nhiều là một mối quan hệ phức tạp hơn, trong đó nhiều bản ghi trong một mô hình có thể được liên kết với nhiều bản ghi trong một mô hình 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 mô hình
Django hỗ trợ kế thừa mô hình, cho phép bạn tạo các mô hình chuyên biệt hơn dựa trên các mô hình 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 cha cho các mô hình 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 dưới dạng 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 mô hình trong hệ thống 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.
Mô hình proxy
Mô hình proxy là một dạng kế thừa mô hình khác, trong đó bạn có thể tạo một mô hình proxy hoạt động giống như mô hình gốc nhưng với một số sửa đổi. Mô hình proxy 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 mô hình.
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 tiễn tốt nhất cho mô hình Django
-
Quy ước đặt tên
- Sử dụng danh từ số ít cho tên lớp mô hình và làm cho chúng mô tả và trực quan.
- Sử dụng các chữ thường và dấu gạch dưới cho tên trường.
- Cân nhắc sử dụng các tên rõ ràng và có ý nghĩa cho các trường để cải thiện khả năng đọc mã.
- Sử dụng danh từ số ít cho tên lớp mô hình và làm cho chúng mô tả và trực quan.
-
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=True
vàunique=True
để đảm bảo tính toàn vẹn dữ liệu.
- Sử dụng
ForeignKey
vàManyToManyField
để thiết lập mối quan hệ giữa các mô hình.
- 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ữ.
-
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 các truy vấn.
- 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.
-
Phương thức và thuộc tính mô hình
- Định nghĩa các phương thức trên các mô hình để đó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 mô hình.
- 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.
- Định nghĩa các phương thức trên các mô hình để đó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 mô hình.
-
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 các mô hình.
- 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 tổ hợp trường duy nhất.
- Sử dụng lớp
-
Sử dụng di chuyển
- Sử dụng hệ thống di chuyển của Django để quản lý các thay đổi đối với lược đồ 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 các mô hình hoặc lược đồ cơ sở dữ liệu.
- Sử dụng hệ thống di chuyển của Django để quản lý các thay đổi đối với lược đồ cơ sở dữ liệu theo thời gian.
-
Kiểm thử
- Viết các bài kiểm thử đơn vị cho các mô hình để đảm bảo hành vi và tương tác của chúng là chính xác.
- Kiểm thử các phương thức, thuộc tính và mối quan hệ của mô hình để xác minh chức năng của chúng.
- Viết các bài kiểm thử đơn vị cho các mô hình để đảm bảo hành vi và tương tác của chúng là chính xác.
-
Tổ chức mã
- Tổ chức các mô hình 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 mô hình một cách hợp lý.
- Tổ chức các mô hình 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.
-
Tài liệu
- Thêm các nhận xét và chuỗi doc vào các mô hình, trường và phương thức để cung cấp tính rõ ràng và làm cho mã dễ hiểu hơn.
- Tài liệu hóa bất kỳ
- Thêm các nhận xét và chuỗi doc vào các mô hình, trường và phương thức để cung cấp tính rõ ràng và làm cho mã dễ hiểu hơn.