介紹
在先前的教程中,“如何創建Django應用程序並將其連接到數據庫”,我們介紹了如何創建一個MySQL數據庫,如何創建和啟動一個Django應用程序,以及如何將其連接到一個MySQL數據庫。
在本教程中,我們將創建Django 模型,這些模型定義了我們將要存儲的Blog應用程序數據的字段和行為。這些模型將從您的Django應用程序映射數據到數據庫。這是Django用來通過它們的對象關係映射(ORM)API生成數據庫表的方式,被稱為“模型”。
先決條件
本教程是“Django開發系列”的一部分,是該系列的延續。
如果您沒有跟隨這個系列,我們做出以下假設:
- 您已安裝了Django版本4或更高版本。
- 你已將你的Django應用連接到數據庫。我們正在使用MySQL,你可以通過遵循Django系列的第二部分“如何創建Django應用程序並將其連接到數據庫”來實現此連接。
- 你正在使用基於Unix的操作系統,最好是Ubuntu 22.04雲伺服器,因為這是我們測試的系統。如果你想在類似的環境中設置Django,請參考我們的教程,“如何在Ubuntu 22.04上安裝Django並設置開發環境”。
由於本教程主要處理Django模型,即使你的設置有些不同,你可能也能夠跟隨進行。
第1步 — 創建Django應用程序
為了與Django的模塊化哲學保持一致,我們將在我們的項目中創建一個Django應用程序,其中包含創建博客網站所需的所有文件。
每當我們開始在Python和Django中進行工作時,我們應該激活我們的Python虛擬環境並移動到我們應用程序的根目錄。如果你跟隨系列,可以通過輸入以下命令實現這一點。
- cd ~/my_blog_app
- . env/bin/activate
- cd blog
然後,讓我們運行這個命令:
- python manage.py startapp blogsite
這將創建我們的應用程序以及一個blogsite
目錄。
在本教程系列的這一部分,您將為您的項目擁有以下目錄結構:
my_blog_app/
└── blog
├── blog
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-38.pyc
│ │ ├── settings.cpython-38.pyc
│ │ ├── urls.cpython-38.pyc
│ │ └── wsgi.cpython-38.pyc
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── blogsite
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py
我們將在本教程中專注的文件將是models.py
文件,它位於blogsite
目錄中。
步驟2 — 添加帖子模型
首先,我們需要打開並編輯models.py
文件,以便其中包含生成Post
模型的代碼。一個Post
模型包含以下數據庫字段:
title
— 博客帖子的標題。slug
— 存儲並生成網頁的有效URL。content
— 博客帖子的文本內容。created_on
— 帖子創建的日期。author
— 撰寫該帖子的人。
現在,進入包含models.py
文件的目錄。
- cd ~/my_blog_app/blog/blogsite
使用cat
命令在終端中顯示文件的內容。
- cat models.py
文件應該包含以下代碼,其中導入了模型,並包含一條注釋描述應將其放入此models.py
文件中的內容。
from django.db import models
# 在這裡創建您的模型。
在您喜歡的文本編輯器中,將以下代碼添加到models.py
文件中。我們將使用nano
作為我們的文本編輯器,但您可以使用您喜歡的任何編輯器。
- nano models.py
在這個文件中,已經添加了用於導入模型API的代碼,我們可以刪除後面的註釋。然後,我們將導入slugify
以從字符串生成slug,導入Django的User
進行身份驗證,以及從django.urls
導入reverse
以在創建URL時提供更大的靈活性。
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverse
然後,添加在我們將要調用的模型類上的類方法Post
,具有以下數據庫字段:title
、slug
、content
、created_on
和author
。將這些添加到您的導入語句下方。
...
class Post(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()
接下來,我們將添加用於生成URL的功能以及保存帖子的功能。這是至關重要的,因為這會創建一個與我們的唯一帖子相匹配的唯一鏈接。
...
def get_absolute_url(self):
return reverse('blog_post_detail', args=[self.slug])
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
現在,我們需要告訴模型帖子應該如何排序,並在網頁上顯示。這個邏輯將被添加到嵌套的內部Meta
類中。Meta
類通常包含其他與數據庫字段定義無關的重要模型邏輯。
...
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.title
最後,我們將在此文件中添加Comment
模型。這涉及添加另一個名為Comment
的類,其簽名中包含models.Models
,並定義以下數據庫字段:
name
— 發表評論的人的名字。email
— 發布評論的人的電子郵件地址。text
— 評論本身的文本。post
— 發布評論的帖子。created_on
— 評論創建時間。
...
class Comment(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)
此時models.py
將完成。 確保您的models.py
文件與以下匹配:
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverse
class Post(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()
def get_absolute_url(self):
return reverse('blog_post_detail', args=[self.slug])
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.title
class Comment(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)
請確保保存並關閉文件。 如果您使用nano,可以通過輸入CTRL
和X
,然後Y
,然後ENTER
來執行此操作。
有了設置好的models.py
文件,我們可以繼續更新我們的settings.py
文件。
步驟3 — 更新設置
現在,我們已經向應用程序添加了模型,我們必須通知我們的項目該應用程序的存在,該應用程序是我們剛剛添加的blogsite
。 我們通過將其添加到settings.py
中的INSTALLED_APPS
部分來完成此操作。
導航到包含您的settings.py
的目錄。
- cd ~/my_blog_app/blog/blog
從這裡,例如使用nano打開您的settings.py
文件。
- nano settings.py
打開文件後,按照下面的說明將您的blogsite
應用程序添加到文件的INSTALLED_APPS
部分。
# 應用程序定義
INSTALLED_APPS = [
'blogsite',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
在添加了blogsite
應用程序後,您可以保存並退出文件。
此時,我們準備好繼續應用這些更改。
步驟 4 —— 進行遷移
在添加了模型Post
和Comment
之後,下一步是應用這些更改,以便我們的MySQL
數據庫架構能識別它們並創建必要的表格。
首先,我們必須使用makemigrations
命令將我們的模型更改打包到個別的遷移文件中。這些文件類似於像Git這樣的版本控制系統中的commits
。
現在,如果您導航到~/my_blog_app/blog/blogsite/migrations
並運行ls
,您會注意到那裡只有一個__init__.py
文件。一旦我們添加了遷移,這將會改變。
使用cd
切換到博客目錄,像這樣:
- cd ~/my_blog_app/blog
然後在manage.py
上運行makemigrations
命令。
- python manage.py makemigrations
之後,您應該在終端窗口中收到以下輸出:
OutputMigrations for 'blogsite':
blogsite/migrations/0001_initial.py
- Create model Post
- Create model Comment
記住,當我們導航到/~/my_blog_app/blog/blogsite/migrations
並且它只有__init__.py
文件時? 如果現在我們cd
回到該目錄,我們會注意到已添加了兩個項目:__pycache__
和0001_initial.py
。 當您運行makemigrations
時,0001_initial.py
文件會自動生成。 每次運行makemigrations
時都會生成一個類似的文件。
從該目錄運行less 0001_initial.py
,如果您想查看文件包含的內容。
現在導航到~/my_blog_app/blog
:
- cd ~/my_blog_app/blog
由於我們已經創建了一個遷移文件,所以我們必須使用migrate
命令將這些文件描述的更改應用到數據庫中。 但首先,讓我們使用showmigrations
命令檢查當前存在哪些遷移。
- python manage.py showmigrations
Outputadmin
[X] 0001_initial
[X] 0002_logentry_remove_auto_add
[X] 0003_logentry_add_action_flag_choices
auth
[X] 0001_initial
[X] 0002_alter_permission_name_max_length
[X] 0003_alter_user_email_max_length
[X] 0004_alter_user_username_opts
[X] 0005_alter_user_last_login_null
[X] 0006_require_contenttypes_0002
[X] 0007_alter_validators_add_error_messages
[X] 0008_alter_user_username_max_length
[X] 0009_alter_user_last_name_max_length
[X] 0010_alter_group_name_max_length
[X] 0011_update_proxy_permissions
blogsite
[ ] 0001_initial
contenttypes
[X] 0001_initial
[X] 0002_remove_content_type_name
sessions
[X] 0001_initial
您會注意到所有遷移都已檢查,除了我們剛剛使用模型Post
和Comment
創建的0001_initial
的遷移。
現在,讓我們檢查一下一旦我們進行遷移,將執行哪些SQL
語句,使用以下命令。 它將遷移和遷移標題作為參數:
- python manage.py sqlmigrate blogsite 0001_initial
下面揭示了在幕後製作的實際SQL查詢。
Output--
-- 創建模型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);
--
-- 創建模型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, `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`);
現在讓我們執行遷移,以便將它們應用到我們的MySQL數據庫中。
- python manage.py migrate
我們將收到以下輸出:
OutputOperations to perform:
Apply all migrations: admin, auth, blogsite, contenttypes, sessions
Running migrations:
Applying blogsite.0001_initial... OK
您現在已成功應用您的遷移。
請注意,在Django文件中指出,使用MySQL作為後端時,Django遷移有三個注意事項。
- 缺乏對模式更改操作的事務支持。換句話說,如果遷移無法成功應用,您將需要手動取消您所做的更改,以嘗試另一個遷移。在失敗的遷移中進行更改之前,不可能回滾到之前的任何更改。
- 對於大多數模式更改操作,MySQL將完全重寫表。在最壞的情況下,時間複雜度將與表中的行數成比例,以添加或刪除列。根據Django文檔,這可能慢到每百萬行一分鐘。
- 在MySQL中,對於列、表和索引的名稱長度有較小的限制。所有列和索引覆蓋的組合大小也有限制。儘管Django中創建的某些其他後端可以支持更高的限制,但在使用MySQL後端時,同樣的索引將無法創建。
對於您考慮與Django一起使用的每個數據庫,請確保權衡每個的優缺點。
步驟5 — 驗證數據庫模式
完成遷移後,我們應該驗證我們通過Django模型創建的MySQL表的成功生成。
要執行這個操作,在終端機中運行以下命令以登錄到MySQL。我們將使用在上一篇教程中創建的djangouser
。
- mysql blog_data -u djangouser
現在,選擇我們的數據庫blog_data
。如果你不知道正在使用的數據庫,你可以在SQL中顯示所有數據庫使用SHOW DATABASES;
。
- USE blog_data;
然後輸入以下命令來查看表格。
- SHOW TABLES;
這個SQL查詢應該顯示以下結果:
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 |
+----------------------------+
12 rows in set (0.01 sec)
在這些表格中包括blogsite_comment
和blogsite_post
。這些是我們剛剛建立的模型。讓我們驗證它們包含我們定義的字段。
- DESCRIBE blogsite_comment;
Output+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int | 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 | NO | MUL | NULL | |
+------------+--------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)
- DESCRIBE blogsite_post;
Output+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int | 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.00 sec)
我們已經驗證數據庫表格已經成功從我們的Django模型遷移生成。
你可以使用CTRL
+ D
退出MySQL,當你準備好離開Python環境時,你可以運行deactivate
命令:
- deactivate
退出你的編程環境將把你返回到終端命令提示符。
結論
在這個教學中,我們已成功在部落格網頁應用程式中添加了基本功能的模型。您已經學會了如何編碼 models
,migrations
的運作方式以及將 Django models
轉換為實際的 MySQL
資料庫表格的過程。
Source:
https://www.digitalocean.com/community/tutorials/how-to-create-django-models