Cách tạo các Django Model

6 năm trước

Cách tạo các Django Model

Mở đầu

 

Trong hướng dẫn này, ta sẽ tạo ra các mô hình (model) để xác định các trường và hành vi của dữ liệu ứng dụng Blog cần được được lưu trữ. Những mô hình này ánh xạ dữ liệu từ ứng dụng Django vào cơ sở dữ liệu và đươc Django sử dụng để tạo ra các bảng trong cơ sở dữ liệu thông qua các API object relational mapping (ORM) gọi là các "model".

 

Yêu cầu

 

Bạn cần có MySQL được cài trên server Ubuntu 16.04, cùng với kết nối đến database được thiết lập qua ứng dụng Django.

Bước 1 — Tạo ứng dụng Django

Để duy trì tính  tương thích với module của Django, ta sẽ tạo một ứng dụng Django bên trong project chứa tất cả các file cần thiết để tạo một Blog.

Đầu tiên kích hoạt môi trường Python ảo:

cd ~/my_blog_app
env/bin/activatecd blog

Sau đó chạy lệnh:

python manage.py startapp blogsite

Đến đây bạn đã có cấu trúc dữ liệu cho project của mình:

my_blog_app/
└── blog
├── blog
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-35.pyc
│ │ ├── settings.cpython-35.pyc
│ │ ├── urls.cpython-35.pyc
│ │ └── wsgi.cpython-35.pyc
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── blogsite
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py

Ta sẽ tập trung vào file models.py trong bài viết này.

Bước 2 — Thêm các Posts Model

 

Đầu tiên ta cần mở file models.py , vì nó chứa đoạn mã nguồn giúp ta tạ ra một Post model. Một Post model sẽ chứa những thuộc tính sau của database:

  • title — Tiêu đề của blog.
  • slug — Nơi các URL được lưu và cung cấp cho cac trang web
  • content — Các thành phần của bài blog post.
  • created_on — Ngày bài post được tạo.
  • author — Tác giả bài post.

Thay đổi thư mục chứa models.py :

cd ~/my_blog_app/blog/blogsite

Dùng lệnh cat để hiển thị các thành phần của file trên terminal.

cat models.py

File này sẽ chứa những dòng code có nhiệm vụ import các model, cùng các comment miêu tả các thành phần của file.

models.py
from django.db import models# Create your models here.

Dùng nano để thay đổi nội dung của file models.py với lệnh:

nano models.py

Trong file này, mã import các model API đã được thêm vào, nên đầu tiên ta chỉ cần xóa dòng comment bên dưới nó. Sau đó ta sẽ import slugify để tạo ra các mã từ các chuỗi, mà  User của Django dùng nó để xác thực.

models.py
from django.db import modelsfrom django.template.defaultfilters import slugifyfrom django.contrib.auth.models import User

Sau đó ta sẽ thêm vào class Post các thuộc tính dựa trên các trường của database như titleslugcontentcreated_on và author.

models.py
...classPost(models.Model): title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.TextField()

Tiếp theo ta sẽ thêm tính năng sinh ra các URL và các chức năng để lưu bài đăng:

models.py
...@models.permalinkdefget_absolute_url(self):return ('blog_post_detail', (),{'slug': self.slug,
})
defsave(self, *args, **kwargs):ifnot self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)

Giờ ta sẽ cho model biết các bài post sẽ được sắp xếp , và hiển thị trên trang web như thế nào. Để làm vậy ta sẽ cần một class Meta được lồng bên trong file cấu hình. Class này chứa những logic cơ bản liên quan đến việc xử lí các trường của database.

models.py
...
classMeta: ordering = ['created_on']
def__unicode__(self):return self.title

Cuối cùng, ta sẽ thêm vào Comment model. Model này bao gồm một class Comment chứa models.Models bên trong nó cùng các trường sau:

  • name — Tên người đăng comment.
  • email — Địa chỉ email của người đăng.
  • text — Nội dung comment.
  • post — Bài post mà comment được đăng.
  • created_on — Thời gian comment được tạo.
models.py
...classComment(models.Model): name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
content = models.TextField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)

File models.py sau khi được chỉnh sửa sẽ trông như sau:

models.py
from django.db import modelsfrom django.template.defaultfilters import slugifyfrom django.contrib.auth.models import UserclassPost(models.Model): title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.TextField()
@models.permalinkdefget_absolute_url(self):return ('blog_post_detail', (),{'slug': self.slug,
})
defsave(self, *args, **kwargs):ifnot self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
classMeta: ordering = ['created_on']
def__unicode__(self):return self.titleclassComment(models.Model): name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
content = models.TextField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)

Lưu và đóng file

 

Bước 3 — Update các cài đặt

Sau khi thêm các model vào ứng dụng, ta cần cho project khả năng tương tác với úng dung blogsite vừa được tạo. Ta sẽ thực hiện điều này bằng việc điều chỉnh mục INSTALLED_APPS trong file settings.py.

Chuyển đến thư mục chứa file settings.py .

cd ~/my_blog_app/blog/blog

Mở file settings.py với nano bằng lệnh nano settings.py.

Sau khi mở file, thêm ưng dụng blogsite vào mục INSTALLED_APPS như sau:

settings.py
# Application definitionINSTALLED_APPS = [
'blogsite','django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

Lưu và đóng file.

 

Bước 4 — Tạo các Migration

 

Với các model Post và Comment được thêm vào, bước tiếp theo là áp dụng những thay đổi để  MySQLdatabase nhận dạng được chúng tà tạo ra các bảng theo yêu cầu.

Đầu tiên ta sẽ cần log in vào MySQL server.

Note: Trong ví dụ này, ta sẽ sử dụng user root và không có mật khẩu, nhưng bạn nên dùng username và password của riêng bạn.

mysql blog_data -u root

Với lệnh SHOW DATABASES; bạn sẽ thu được output như sau:

Output+--------------------+
| Database |
+--------------------+
| information_schema |
| blog_data |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)

Chọn database  blog_data :

USE blog_data;

Hiển thị danh sách các bảng trong blog_data :

SHOW TABLES;
OutputEmpty set (0.00 sec)

Không có bảng nào được hiển thị vì ta chưa tạo ra migration nào. Nhưng bất cứ khi nào ta tạo ra các migration, chúng sẽ được hiển thị trên các bảng được tạo bởi Django.

Giờ ta sẽ tạo ra migration áp dụng những cài đặt đã được ta cấu hình sẵn ở models.py.

Thoát My SQL với tổ hợp phím CTRL + D.

Đầu tiên ta cần đóng gói các thay đổi của model thành các file migration riêng biệt với lệnh makemigrations. Các file này gần giống với các commits trong các hệ điều khiển dữ liệu như git.

Giờ nếu truy cập vào ~/my_blog_app/blog/blogsite/migrations và chạy lệnh ls, bạn sẽ thấy có một file duy nhất là __init__.py .

Thay đổi thư mục của blog với lệnh cd, rồi tạo file migration với lệnh makemigrations

cd ~/my_blog_app/blog
python manage.py makemigrations

Bạn sẽ thu được Output như sau:

OutputMigrations for 'blogsite':
blogsite/migrations/0001_initial.py
- Create model Comment
- Create model Post
- Add field post to comment

Lần đầu khi chuyển đến thư mục /~/my_blog_app/blog/blogsite/migrations , nó chỉ chứa một file duy nhất là __init__.py . Nếu giờ ta dùng lệnh cd để truy cập trở lại thư mục ấy, sẽ có thêm 2 file được thêm vào, __pycache__ và 0001_initial.py. File 0001_initial.py được tạo tự động khi chạy lệnh makemigrations, và mỗi lần bạn chạy lệnh  makemigrations, một file như thế sẽ được tạo ra ở thư mục này.

Giờ hãy chuyển sang thư mục ~/my_blog_app/blog.

Vì ta đã có một file migration, ta cần phải áp dụng những cài đặt trên các file này lên database với lệnh migrate

Đầu tiê hãy dùng showmigrationscommand để hiển thị danh sách các migration hiện tại:

python manage.py showmigrations
Outputadmin
[ ] 0001_initial
[ ] 0002_logentry_remove_auto_add
auth
[ ] 0001_initial
[ ] 0002_alter_permission_name_max_length
[ ] 0003_alter_user_email_max_length
[ ] 0004_alter_user_username_opts
[ ] 0005_alter_user_last_login_null
[ ] 0006_require_contenttypes_0002
[ ] 0007_alter_validators_add_error_messages
[ ] 0008_alter_user_username_max_length
[ ] 0009_alter_user_last_name_max_length
blogsite
[ ] 0001_initial
contenttypes
[ ] 0001_initial
[ ] 0002_remove_content_type_name
sessions
[ ] 0001_initial
 

Bạn sẽ thấy migration blogsite, chứa migration 0001_initial cho các model Post và Comment được hiển thị.

Giờ hãy xem các lệnh SQL được triển khai khi ta tạo ra migration, với các lệnh dưới đây.

python manage.py sqlmigrate blogsite 0001_initial

Đây là các lệnh SQL được thực hiện trên database sau lệnh trên:

BEGIN;
--
-- Create model Comment
--
CREATE TABLE `blogsite_comment` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(42) NOT NULL, `email` varchar(75) NOT NULL, `website` varchar(200) NULL, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL);
--
-- Create model Post
--
CREATE TABLE `blogsite_post` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `title` varchar(255) NOT NULL, `slug` varchar(255) NOT NULL UNIQUE, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL, `author` longtext NOT NULL);
--
-- Add field post to comment
--
ALTER TABLE `blogsite_comment` ADD COLUMN `post_id` integer NOT NULL;
ALTER TABLE `blogsite_comment` ADD CONSTRAINT `blogsite_comment_post_id_de248bfe_fk_blogsite_post_id` FOREIGN KEY (`post_id`) REFERENCES `blogsite_post` (`id`);
COMMIT;

Giờ hãy biểu diễn các migration để chúng được áp dụng vào MySQL database.

python manage.py migrate
OutputOperations to perform:
Apply all migrations: admin, auth, blogsite, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying blogsite.0001_initial... OK
Applying sessions.0001_initial... OK

Vậy là các migration đã được áp dụng thành công.

Ghi nhớ 3 cảnh báo sau về việc áp dụng các Django migration trên backend là MySQL:

  • Thiếu sự hỗ trợ khi việc áp dụng migration thất bại. Nói cách khác, nếu một migration được áp dụng không thành công, bạn sẽ phải tự gỡ bỏ thay đổi bạn đã thực hiện để thực hiện migration khác mà không thể rollback đến trạng thái trước đó của database.
  • Với hầu hết các hoạt động làm thay đổi sơ đồ của MySQL sẽ hoàn toàn viết lại bảng. Trong trường hợp xấu nhất, độ phức tạp thời gian có tỷ lệ thuận với số lượng hàng trong bảng khi muốn thêm hoặc xóa cột. Theo tài liệu hướng dẫn từ Django, khoảng thời gian trễ này có thể lên đến một phút cho một triệu hàng.
  • Trong MySQL, có những giới hạn nhỏ của độ dài tên cho các cột, bảng và các chỉ số. Ngoài ra còn có một giới hạn về kích thước tổng cộng của tất cả các cột với chỉ số của chúng. Trong khi một số backend khác có thể hỗ trợ giới hạn cao hơn tạo ra trong Django, các chỉ số tương tự sẽ không được  với một backend MySQL.

Hãy cân nhắc các ưu nhược điểm với từng database để sử dụng Django hiệu quả.

Bước 5 — Kiểm tra Lược đồ Database

 

Đầu tiên, log in vào MySQL.

mysql blog_data -u root

Hiển thị các databasei:

SHOW DATABASES;

Chọn database  blog_data:

USE blog_data;

Hiển thị các bảng:

SHOW TABLES;

Bạn sẽ thu được:

Output+----------------------------+
| Tables_in_blog_data |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| blogsite_comment |
| blogsite_post |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+

Bạn sẽ thấy các model blogsite_comment và blogsite_post vừa được tạo. Giờ hãy kiểm tả xem chúng có chứa những trường như ta đã thiết lập hay không

DESCRIBE blogsite_comment;
Output+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(42) | NO | | NULL | |
| email | varchar(75) | NO | | NULL | |
| website | varchar(200) | YES | | NULL | |
| content | longtext | NO | | NULL | |
| created_on | datetime(6) | NO | | NULL | |
| post_id | int(11) | NO | MUL | NULL | |
+------------+--------------+------+-----+---------+----------------+
7 rows in set (0.01 sec)
 
DESCRIBE blogsite_post;
Output:+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| slug | varchar(255) | NO | UNI | NULL | |
| content | longtext | NO | | NULL | |
| created_on | datetime(6) | NO | | NULL | |
| author | longtext | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)
 

Thoát MySQL với tổ hợp phím CTRL + D và deactivate môi trường Python:

deactivate

Tổng kết

Trong bài viết này, ta đã thêm vào các model với những chức năng cơ bản cho một ứng dụng web blog. Bạn đã biết cách code các models, cách các migrations hoạt động và quá trình xử lí các Django models qua các bảng của MySQL database.