第一章 Django ORM 概述
1.1 什么是Django ORM
1.1.1 ORM的基本概念
ORM 即對象關系映射(Object Relational Mapping),它是一種編程技術,用于在面向對象編程語言(如 Python)和關系型數據庫(如 MySQL、PostgreSQL 等)之間建立一座橋梁 🌉。
在傳統的數據庫操作中,我們需要編寫 SQL 語句來完成數據的增刪改查操作。而 ORM 則允許我們使用面向對象的方式來操作數據庫,將數據庫中的表映射為 Python 中的類,表中的每一行記錄映射為類的一個實例對象,表中的列映射為類的屬性。
例如,假設有一個用戶表 users
,包含 id
、name
、age
三列。使用 ORM 后,我們可以創建一個 User
類:
class User:def __init__(self, id, name, age):self.id = idself.name = nameself.age = age
這樣,我們就可以通過操作 User
類的對象來間接操作數據庫中的 users
表,而不需要直接編寫 SQL 語句。
1.1.2 Django ORM的特點
- 簡潔易用:Django ORM 提供了非常簡潔的 API,讓我們可以用很少的代碼完成復雜的數據庫操作。例如,要查詢所有年齡大于 18 歲的用戶,只需要這樣寫:
from myapp.models import User
users = User.objects.filter(age__gt=18)
- 自動生成 SQL:我們不需要手動編寫復雜的 SQL 語句,Django ORM 會根據我們的操作自動生成相應的 SQL 語句并執行。這樣可以減少出錯的概率,提高開發效率。
- 支持事務處理:Django ORM 支持數據庫事務,確保一組數據庫操作要么全部成功,要么全部失敗。例如:
from django.db import transaction@transaction.atomic
def transfer_money(from_account, to_account, amount):from_account.balance -= amountfrom_account.save()to_account.balance += amountto_account.save()
- 支持模型遷移:當我們修改了模型類的定義(如添加或刪除字段),Django ORM 可以自動生成數據庫遷移腳本,幫助我們更新數據庫結構。
1.2 Django ORM的優勢
1.2.1 提高開發效率
- 減少代碼量:使用 Django ORM 可以避免編寫大量重復的 SQL 語句,開發人員可以專注于業務邏輯的實現。例如,在創建一個新用戶時,只需要創建一個
User
類的實例并保存即可:
user = User(name='John', age=20)
user.save()
- 快速開發:Django ORM 的簡潔 API 使得開發人員可以快速完成數據庫操作的開發,縮短開發周期。
1.2.2 數據庫無關性
Django ORM 支持多種數據庫,如 MySQL、PostgreSQL、SQLite 等。我們可以在不修改業務代碼的情況下,輕松地切換數據庫。例如,在開發階段可以使用 SQLite 進行快速開發和測試,在生產環境中可以切換到 MySQL 或 PostgreSQL。
只需要在 settings.py
文件中修改數據庫配置:
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'mydatabase','USER': 'myuser','PASSWORD': 'mypassword','HOST': 'localhost','PORT': '3306',}
}
1.2.3 安全性
- 防止 SQL 注入:Django ORM 會自動對用戶輸入進行轉義,避免 SQL 注入攻擊。例如,當我們使用
filter
方法進行查詢時,用戶輸入的數據會被安全地處理:
username = request.GET.get('username')
users = User.objects.filter(username=username)
- 權限管理:Django 提供了完善的權限管理系統,可以對數據庫操作進行細粒度的權限控制,確保只有授權的用戶才能進行敏感的數據庫操作。
總之,Django ORM 為我們提供了一種高效、安全、便捷的方式來操作數據庫,是 Django 框架的重要組成部分 🚀。
第二章 Django ORM 環境搭建
2.1 安裝Django
2.1.1 使用pip安裝
pip
是 Python 的包管理工具,使用它可以方便快捷地安裝 Django。在安裝之前,請確保你的 Python 環境已經安裝并且 pip
可以正常使用。
在命令行中輸入以下命令來安裝 Django:
pip install django
執行這個命令后,pip
會自動從 Python Package Index(PyPI)下載 Django 的最新版本并安裝到你的 Python 環境中。安裝過程中,你會看到命令行輸出下載和安裝的進度信息,當看到類似“Successfully installed django-xxx”的提示時,就表示 Django 已經安裝成功啦😎。
2.1.2 版本選擇
Django 有不同的版本,每個版本都有其特點和適用場景。在選擇版本時,需要考慮以下因素:
- 穩定性:如果你是用于生產環境,建議選擇長期支持(LTS)版本,這些版本會得到官方更長時間的維護和更新,穩定性更高。例如 Django 3.2 就是一個長期支持版本。
- 新特性:如果你想嘗試新的功能和特性,可以選擇較新的版本。不過新的版本可能存在一些潛在的問題,需要謹慎使用。
- 兼容性:要確保你選擇的 Django 版本與你使用的 Python 版本以及其他依賴庫兼容。
如果你想安裝指定版本的 Django,可以在安裝命令中指定版本號,例如:
pip install django==3.2
這樣就會安裝 Django 3.2 版本。
2.2 配置數據庫
2.2.1 支持的數據庫類型
Django 支持多種數據庫類型,你可以根據項目的需求選擇合適的數據庫:
- SQLite:這是 Django 默認使用的數據庫,它是一個輕量級的嵌入式數據庫,不需要單獨的服務器進程,適合開發和測試環境。SQLite 的文件存儲在本地,使用起來非常方便,就像一個小型的文件數據庫一樣🤗。
- PostgreSQL:是一個功能強大的開源關系型數據庫,支持高級的 SQL 特性和并發操作。它在性能、可靠性和擴展性方面都表現出色,常用于生產環境。
- MySQL:也是一種廣泛使用的開源關系型數據庫,具有高性能、穩定性和易用性等特點。很多大型網站和應用都使用 MySQL 作為數據庫。
- Oracle:是一種商業數據庫,具有強大的功能和高可用性,適用于大型企業級應用。
2.2.2 數據庫連接配置
在 Django 項目中,數據庫連接配置通常在 settings.py
文件中進行。以下是不同數據庫的配置示例:
SQLite 配置
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': BASE_DIR / 'db.sqlite3',}
}
這里 ENGINE
指定了使用的數據庫引擎,NAME
指定了 SQLite 數據庫文件的路徑。
PostgreSQL 配置
DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql','NAME': 'your_database_name','USER': 'your_username','PASSWORD': 'your_password','HOST': 'your_host','PORT': 'your_port',}
}
需要將 your_database_name
、your_username
、your_password
、your_host
和 your_port
替換為你自己的數據庫信息。
MySQL 配置
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'your_database_name','USER': 'your_username','PASSWORD': 'your_password','HOST': 'your_host','PORT': 'your_port',}
}
同樣,要將相應的信息替換為你自己的數據庫信息。
2.3 創建Django項目和應用
2.3.1 創建項目命令
在命令行中,使用以下命令來創建一個新的 Django 項目:
django-admin startproject your_project_name
其中 your_project_name
是你想要創建的項目名稱。執行這個命令后,Django 會在當前目錄下創建一個新的項目目錄,目錄結構如下:
your_project_name/
├── manage.py
└── your_project_name/├── __init__.py├── settings.py├── urls.py└── wsgi.py
manage.py
:是一個命令行工具,用于與 Django 項目進行交互,例如啟動開發服務器、創建數據庫表等。settings.py
:包含了項目的配置信息,如數據庫配置、中間件配置等。urls.py
:定義了項目的 URL 路由規則。wsgi.py
:是一個 WSGI 兼容的 Web 服務器的入口點。
2.3.2 創建應用命令
在 Django 中,一個項目可以包含多個應用,每個應用負責不同的功能。使用以下命令來創建一個新的應用:
python manage.py startapp your_app_name
其中 your_app_name
是你想要創建的應用名稱。執行這個命令后,Django 會在項目目錄下創建一個新的應用目錄,目錄結構如下:
your_app_name/
├── __init__.py
├── admin.py
├── apps.py
├── migrations/
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
admin.py
:用于配置 Django 管理界面。models.py
:定義了應用的數據模型。views.py
:包含了處理用戶請求的視圖函數。
2.3.3 注冊應用
創建好應用后,需要在項目的 settings.py
文件中注冊應用,這樣 Django 才能識別并使用這個應用。打開 settings.py
文件,找到 INSTALLED_APPS
列表,將你的應用名稱添加到列表中:
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','your_app_name', # 添加你的應用名稱
]
這樣,你的應用就成功注冊到項目中啦🎉。
第三章 模型定義
在軟件開發中,尤其是使用 Django 等框架進行數據庫操作時,模型定義是非常重要的一環,它就像是數據庫表結構的藍圖,規定了數據的存儲方式和關系。下面我們來詳細了解模型定義的各個方面。
3.1 模型類的創建
3.1.1 模型類的基本結構
模型類就像是一個模板,它定義了數據庫表中的字段和行為。在 Django 中,一個基本的模型類通常包含類名、字段定義和一些可選的方法。以下是一個簡單的示例:
from django.db import modelsclass Book(models.Model):title = models.CharField(max_length=100)author = models.CharField(max_length=50)publication_date = models.DateField()def __str__(self):return self.title
from django.db import models
:導入 Django 的模型模塊。class Book(models.Model)
:定義一個名為Book
的模型類,繼承自models.Model
。title = models.CharField(max_length=100)
:定義一個字符型字段title
,最大長度為 100。author = models.CharField(max_length=50)
:定義一個字符型字段author
,最大長度為 50。publication_date = models.DateField()
:定義一個日期型字段publication_date
。def __str__(self)
:定義一個方法,用于返回對象的字符串表示,方便在調試和管理界面中顯示。
3.1.2 繼承關系
在 Django 中,模型類可以通過繼承來復用代碼和實現特定的功能。常見的繼承方式有以下幾種:
- 抽象基類繼承:抽象基類是一種不能直接實例化的類,它主要用于定義一些通用的字段和方法,供其他模型類繼承。示例如下:
from django.db import modelsclass BaseModel(models.Model):created_at = models.DateTimeField(auto_now_add=True)updated_at = models.DateTimeField(auto_now=True)class Meta:abstract = Trueclass Book(BaseModel):title = models.CharField(max_length=100)author = models.CharField(max_length=50)
在這個例子中,BaseModel
是一個抽象基類,它定義了 created_at
和 updated_at
字段,用于記錄數據的創建和更新時間。Book
類繼承自 BaseModel
,并添加了自己的字段。
- 多表繼承:多表繼承是指一個模型類繼承自另一個具體的模型類,每個模型類對應一個數據庫表。示例如下:
from django.db import modelsclass Person(models.Model):name = models.CharField(max_length=50)class Student(Person):student_id = models.CharField(max_length=20)
在這個例子中,Student
類繼承自 Person
類,Person
和 Student
分別對應兩個數據庫表,Student
表會包含 Person
表的所有字段以及自己的 student_id
字段。
3.2 字段類型
3.2.1 常見字段類型
在 Django 中,有多種字段類型可供選擇,用于存儲不同類型的數據。以下是一些常見的字段類型:
-
字符型字段:
CharField
:用于存儲較短的字符串,需要指定max_length
參數。例如:title = models.CharField(max_length=100)
。TextField
:用于存儲較長的文本,不需要指定最大長度。例如:description = models.TextField()
。
-
數值型字段:
IntegerField
:用于存儲整數。例如:age = models.IntegerField()
。FloatField
:用于存儲浮點數。例如:price = models.FloatField()
。
-
日期和時間型字段:
DateField
:用于存儲日期。例如:birth_date = models.DateField()
。DateTimeField
:用于存儲日期和時間。例如:created_at = models.DateTimeField(auto_now_add=True)
。
-
布爾型字段:
BooleanField
:用于存儲布爾值(True
或False
)。例如:is_published = models.BooleanField(default=False)
。
3.2.2 字段選項
每個字段類型都可以有一些選項,用于進一步定義字段的行為。以下是一些常見的字段選項:
null
:如果設置為True
,表示該字段在數據庫中可以為空。例如:email = models.CharField(max_length=100, null=True)
。blank
:如果設置為True
,表示該字段在表單中可以為空。例如:phone = models.CharField(max_length=20, blank=True)
。default
:設置字段的默認值。例如:status = models.CharField(max_length=20, default='active')
。unique
:如果設置為True
,表示該字段的值在表中必須唯一。例如:username = models.CharField(max_length=50, unique=True)
。
3.3 模型元數據
3.3.1 Meta 類的作用
在 Django 模型類中,可以定義一個內部類 Meta
,用于提供模型的元數據。元數據是指與模型本身相關的一些信息,而不是模型的字段信息。Meta
類的主要作用包括:
- 定義模型的數據庫表名。
- 定義模型的排序方式。
- 定義模型的可讀名稱。
3.3.2 常用元數據選項
以下是一些常用的 Meta
類選項:
db_table
:指定模型對應的數據庫表名。例如:
class Book(models.Model):title = models.CharField(max_length=100)class Meta:db_table = 'my_books'
在這個例子中,Book
模型對應的數據庫表名是 my_books
。
ordering
:指定模型的排序方式。例如:
class Book(models.Model):title = models.CharField(max_length=100)publication_date = models.DateField()class Meta:ordering = ['-publication_date']
在這個例子中,Book
模型的對象將按照 publication_date
字段降序排列。
verbose_name
和verbose_name_plural
:定義模型的可讀名稱和復數形式的可讀名稱。例如:
class Book(models.Model):title = models.CharField(max_length=100)class Meta:verbose_name = '圖書'verbose_name_plural = '圖書列表'
在這個例子中,Book
模型在管理界面中顯示為“圖書”,復數形式顯示為“圖書列表”。
3.4 模型關系
3.4.1 一對一關系
一對一關系是指一個模型的實例與另一個模型的實例之間存在一一對應的關系。在 Django 中,可以使用 OneToOneField
來定義一對一關系。示例如下:
from django.db import modelsclass Profile(models.Model):user = models.OneToOneField('auth.User', on_delete=models.CASCADE)bio = models.TextField()
在這個例子中,Profile
模型與 auth.User
模型之間存在一對一關系,即每個用戶只能有一個個人資料。on_delete=models.CASCADE
表示當關聯的用戶被刪除時,對應的個人資料也會被刪除。
3.4.2 一對多關系
一對多關系是指一個模型的實例可以與另一個模型的多個實例相關聯。在 Django 中,可以使用 ForeignKey
來定義一對多關系。示例如下:
from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=50)class Book(models.Model):title = models.CharField(max_length=100)author = models.ForeignKey(Author, on_delete=models.CASCADE)
在這個例子中,Book
模型與 Author
模型之間存在一對多關系,即一個作者可以有多本書。on_delete=models.CASCADE
表示當關聯的作者被刪除時,對應的書籍也會被刪除。
3.4.3 多對多關系
多對多關系是指一個模型的多個實例可以與另一個模型的多個實例相關聯。在 Django 中,可以使用 ManyToManyField
來定義多對多關系。示例如下:
from django.db import modelsclass Tag(models.Model):name = models.CharField(max_length=20)class Book(models.Model):title = models.CharField(max_length=100)tags = models.ManyToManyField(Tag)
在這個例子中,Book
模型與 Tag
模型之間存在多對多關系,即一本書可以有多個標簽,一個標簽也可以應用于多本書。Django 會自動創建一個中間表來管理這種關系。
通過以上內容,我們詳細了解了模型定義的各個方面,包括模型類的創建、字段類型、模型元數據和模型關系。這些知識對于使用 Django 等框架進行數據庫操作非常重要。🎉
第四章 數據庫遷移
在 Django 項目中,數據庫遷移是一個非常重要的功能,它允許我們在模型發生變化時,安全地更新數據庫結構,而不會丟失數據。下面我們來詳細了解數據庫遷移的相關內容。
4.1 遷移文件的生成
4.1.1 makemigrations 命令
在 Django 里,makemigrations
命令就像是一個“變化探測器”😎。當我們對模型(models.py
文件中的類)進行了修改,比如添加了新的字段、刪除了某個字段或者修改了字段的屬性,就需要使用這個命令來生成遷移文件。
- 使用方法:在命令行中,進入項目的根目錄,然后輸入以下命令:
python manage.py makemigrations
- 執行過程:Django 會自動檢測模型的變化,然后將這些變化轉換為 Python 代碼,保存到一個新的遷移文件中。這些遷移文件通常存放在應用的
migrations
文件夾下。 - 指定應用:如果你的項目中有多個應用,你也可以指定只對某個應用生成遷移文件,命令如下:
python manage.py makemigrations app_name
這里的 app_name
就是你要指定的應用名稱。
4.1.2 遷移文件的結構
遷移文件是一個 Python 文件,它包含了對數據庫結構的修改信息。下面是一個簡單的遷移文件示例:
# -*- coding: utf-8 -*-
from django.db import migrations, modelsclass Migration(migrations.Migration):initial = Truedependencies = []operations = [migrations.CreateModel(name='Book',fields=[('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),('title', models.CharField(max_length=100)),('author', models.CharField(max_length=100)),],),]
initial
:如果這個值為True
,表示這是該應用的第一個遷移文件。dependencies
:指定該遷移文件依賴的其他遷移文件。如果沒有依賴,列表為空。operations
:這是遷移文件的核心部分,它包含了一系列的操作,比如創建模型、添加字段、刪除字段等。在上面的示例中,migrations.CreateModel
表示創建一個名為Book
的模型。
4.2 執行遷移
4.2.2 migrate 命令
migrate
命令就像是一個“數據庫更新器”🚀,它會將之前生成的遷移文件應用到數據庫中,從而更新數據庫的結構。
- 使用方法:在命令行中,進入項目的根目錄,然后輸入以下命令:
python manage.py migrate
- 執行過程:Django 會檢查所有應用的遷移文件,找出那些還沒有應用到數據庫中的遷移文件,然后按照依賴關系依次執行這些遷移文件中的操作。
- 指定應用:和
makemigrations
命令一樣,你也可以指定只對某個應用執行遷移,命令如下:
python manage.py migrate app_name
4.2.2 遷移歷史記錄
Django 會在數據庫中創建一個名為 django_migrations
的表,用來記錄所有的遷移歷史。這個表包含了遷移文件的名稱、應用名稱和應用時間等信息。
- 查看遷移歷史:你可以使用以下命令查看某個應用的遷移歷史:
python manage.py showmigrations app_name
在輸出結果中,[X]
表示該遷移文件已經應用到數據庫中,[ ]
表示還沒有應用。
4.3 回滾遷移
4.3.1 回滾到指定版本
有時候,我們可能需要將數據庫回滾到某個之前的版本。這時可以使用 migrate
命令加上遷移文件的名稱來實現。
- 使用方法:在命令行中,進入項目的根目錄,然后輸入以下命令:
python manage.py migrate app_name migration_name
這里的 app_name
是應用名稱,migration_name
是你要回滾到的遷移文件的名稱。
4.3.2 撤銷未應用的遷移
如果有一些遷移文件還沒有應用到數據庫中,你可以使用 migrate
命令加上 zero
來撤銷這些未應用的遷移。
- 使用方法:在命令行中,進入項目的根目錄,然后輸入以下命令:
python manage.py migrate app_name zero
這個命令會撤銷該應用所有未應用的遷移文件。
通過以上這些操作,我們可以靈活地管理數據庫的遷移,確保數據庫結構和模型保持一致。😃
第五章 數據查詢
5.1 查詢集的基本操作
5.1.1 獲取查詢集
查詢集(QuerySet)是 Django 中用于從數據庫中獲取對象集合的一種方式😃。可以通過模型類名直接調用方法來獲取查詢集。例如,假設有一個 Book
模型類,以下代碼可以獲取所有的 Book
對象組成的查詢集:
from yourapp.models import Bookbooks = Book.objects.all()
這里的 Book.objects.all()
就返回了一個查詢集,它包含了 Book
模型在數據庫中的所有記錄📚。查詢集就像是一個可迭代的對象列表,你可以對它進行各種操作。
5.1.2 過濾查詢集
過濾查詢集可以讓你從查詢集中篩選出符合特定條件的對象。可以使用 filter()
方法來實現過濾。例如,要篩選出出版年份為 2023 年的 Book
對象:
from yourapp.models import Bookbooks_2023 = Book.objects.filter(pub_year=2023)
這里的 pub_year
是 Book
模型中的一個字段,filter(pub_year=2023)
表示篩選出 pub_year
字段值為 2023 的對象。還可以使用多個條件進行過濾,多個條件之間是“與”的關系:
books_2023_and_price_50 = Book.objects.filter(pub_year=2023, price=50)
5.1.3 排序查詢集
排序查詢集可以按照指定的字段對查詢集中的對象進行排序。可以使用 order_by()
方法來實現排序。例如,要按照價格從低到高對 Book
對象進行排序:
from yourapp.models import Bookbooks_ordered_by_price = Book.objects.all().order_by('price')
這里的 order_by('price')
表示按照 price
字段進行升序排序。如果要進行降序排序,可以在字段名前加一個負號:
books_ordered_by_price_desc = Book.objects.all().order_by('-price')
5.1.4 切片查詢集
切片查詢集可以從查詢集中獲取指定范圍的對象,類似于 Python 列表的切片操作。例如,要獲取前 5 本 Book
對象:
from yourapp.models import Bookfirst_five_books = Book.objects.all()[:5]
這里的 [:5]
表示從查詢集的開頭開始取 5 個對象。也可以指定起始和結束位置,例如獲取第 3 到第 6 本 Book
對象:
third_to_sixth_books = Book.objects.all()[2:6]
5.2 常用查詢方法
5.2.1 get()方法
get()
方法用于從數據庫中獲取滿足特定條件的單個對象。如果查詢結果有且只有一個對象,則返回該對象;如果查詢結果為空或有多個對象,則會拋出異常。例如,要獲取 id
為 1 的 Book
對象:
from yourapp.models import Booktry:book = Book.objects.get(id=1)print(book.title)
except Book.DoesNotExist:print("沒有找到該書籍!")
except Book.MultipleObjectsReturned:print("查詢結果有多個對象!")
5.2.2 filter()方法
filter()
方法前面已經介紹過,它用于從查詢集中篩選出符合特定條件的對象,返回一個新的查詢集。可以使用各種字段和條件進行篩選,例如:
from yourapp.models import Book# 篩選出價格大于 50 的書籍
expensive_books = Book.objects.filter(price__gt=50)
這里的 __gt
是 Django 中的查詢字段修飾符,表示“大于”的意思。
5.2.3 exclude()方法
exclude()
方法用于從查詢集中排除符合特定條件的對象,返回一個新的查詢集。例如,要排除價格為 50 的 Book
對象:
from yourapp.models import Bookbooks_not_50 = Book.objects.exclude(price=50)
5.2.4 all()方法
all()
方法用于獲取模型在數據庫中的所有對象組成的查詢集。例如:
from yourapp.models import Bookall_books = Book.objects.all()
5.3 復雜查詢
5.3.1 Q對象
Q
對象用于在查詢中實現復雜的邏輯組合,例如“或”關系。在 Django 中,默認的多個條件是“與”關系,使用 Q
對象可以實現“或”關系。例如,要篩選出價格大于 50 或者出版年份為 2023 年的 Book
對象:
from yourapp.models import Book
from django.db.models import Qbooks = Book.objects.filter(Q(price__gt=50) | Q(pub_year=2023))
這里的 |
表示“或”關系,Q(price__gt=50)
和 Q(pub_year=2023)
是兩個 Q
對象。
5.3.2 F對象
F
對象用于在查詢中引用模型的字段,實現字段之間的比較。例如,要篩選出價格大于庫存數量的 Book
對象:
from yourapp.models import Book
from django.db.models import Fbooks = Book.objects.filter(price__gt=F('stock'))
這里的 F('stock')
表示引用 Book
模型中的 stock
字段。
5.3.3 聚合查詢
聚合查詢用于對查詢集中的對象進行統計計算,例如求和、平均值、最大值、最小值等。可以使用 aggregate()
方法來實現聚合查詢。例如,要計算所有 Book
對象的平均價格:
from yourapp.models import Book
from django.db.models import Avgresult = Book.objects.aggregate(Avg('price'))
average_price = result['price__avg']
print(f"平均價格為: {average_price}")
5.3.4 分組查詢
分組查詢用于按照指定的字段對查詢集中的對象進行分組,并對每個組進行聚合計算。可以使用 values()
和 annotate()
方法來實現分組查詢。例如,要按照出版年份對 Book
對象進行分組,并計算每個組的平均價格:
from yourapp.models import Book
from django.db.models import Avggrouped_books = Book.objects.values('pub_year').annotate(avg_price=Avg('price'))
for group in grouped_books:print(f"出版年份: {group['pub_year']}, 平均價格: {group['avg_price']}")
這里的 values('pub_year')
表示按照 pub_year
字段進行分組,annotate(avg_price=Avg('price'))
表示對每個組計算平均價格。
第六章 數據操作
在數據庫操作中,數據操作是非常重要的一部分,它主要包括創建數據、更新數據和刪除數據。下面我們來詳細了解每一種操作的具體方法。
6.1 創建數據
創建數據是向數據庫中添加新記錄的過程,這里我們介紹兩種常用的方法。
6.1.1 使用 create()
方法
create()
方法是一種便捷的創建數據的方式,它可以一次性完成數據的創建和保存操作。以下是使用 create()
方法的步驟和示例:
-
步驟:
- 定義數據模型:首先需要定義一個數據模型,它規定了數據的結構和類型。
- 調用
create()
方法:在數據模型上調用create()
方法,并傳入要創建的數據對象。
-
示例:假設我們有一個用戶模型
User
,包含name
和age
兩個字段。
# 定義用戶模型
from django.db import modelsclass User(models.Model):name = models.CharField(max_length=100)age = models.IntegerField()# 使用 create() 方法創建新用戶
new_user = User.objects.create(name='Alice', age=25)
在這個示例中,我們通過 User.objects.create()
方法創建了一個新的用戶記錄,并將其保存到數據庫中。😃
6.1.2 使用 save()
方法
save()
方法是另一種創建數據的方式,它需要先創建一個數據對象,然后調用 save()
方法將其保存到數據庫中。以下是使用 save()
方法的步驟和示例:
-
步驟:
- 定義數據模型:同樣需要先定義一個數據模型。
- 創建數據對象:根據數據模型創建一個數據對象,并設置其屬性。
- 調用
save()
方法:在數據對象上調用save()
方法,將其保存到數據庫中。
-
示例:還是以用戶模型
User
為例。
# 定義用戶模型
from django.db import modelsclass User(models.Model):name = models.CharField(max_length=100)age = models.IntegerField()# 創建新用戶對象
new_user = User(name='Bob', age=30)
# 保存新用戶對象到數據庫
new_user.save()
在這個示例中,我們先創建了一個 User
對象 new_user
,然后調用 save()
方法將其保存到數據庫中。🤗
6.2 更新數據
更新數據是對數據庫中已有的記錄進行修改的過程,這里我們也介紹兩種常用的方法。
6.2.1 使用 save()
方法
save()
方法不僅可以用于創建數據,還可以用于更新數據。以下是使用 save()
方法更新數據的步驟和示例:
-
步驟:
- 查詢要更新的記錄:使用查詢方法找到要更新的記錄。
- 修改記錄的屬性:在查詢到的記錄對象上修改其屬性。
- 調用
save()
方法:在修改后的記錄對象上調用save()
方法,將修改保存到數據庫中。
-
示例:假設我們要將用戶
Alice
的年齡更新為 26。
# 查詢用戶 Alice
user = User.objects.get(name='Alice')
# 修改用戶的年齡
user.age = 26
# 保存修改到數據庫
user.save()
在這個示例中,我們先通過 get()
方法查詢到用戶 Alice
,然后修改其 age
屬性,最后調用 save()
方法將修改保存到數據庫中。😎
6.2.2 使用 update()
方法
update()
方法可以直接在查詢集上進行批量更新操作。以下是使用 update()
方法更新數據的步驟和示例:
-
步驟:
- 查詢要更新的記錄集:使用查詢方法找到要更新的記錄集。
- 調用
update()
方法:在查詢集上調用update()
方法,并傳入要更新的字段和值。
-
示例:假設我們要將所有用戶的年齡都加 1。
# 查詢所有用戶記錄集
users = User.objects.all()
# 批量更新用戶的年齡
users.update(age=models.F('age') + 1)
在這個示例中,我們先通過 all()
方法查詢到所有用戶記錄集,然后使用 update()
方法將所有用戶的年齡都加 1。這里使用了 models.F()
來引用字段的值。😜
6.3 刪除數據
刪除數據是從數據庫中移除記錄的過程,這里我們介紹兩種常用的方法。
6.3.1 使用 delete()
方法
delete()
方法可以用于刪除單個記錄或記錄集。以下是使用 delete()
方法刪除數據的步驟和示例:
-
步驟:
- 查詢要刪除的記錄或記錄集:使用查詢方法找到要刪除的記錄或記錄集。
- 調用
delete()
方法:在查詢到的記錄或記錄集上調用delete()
方法,將其從數據庫中刪除。
-
示例:假設我們要刪除用戶
Bob
。
# 查詢用戶 Bob
user = User.objects.get(name='Bob')
# 刪除用戶 Bob
user.delete()
在這個示例中,我們先通過 get()
方法查詢到用戶 Bob
,然后調用 delete()
方法將其從數據庫中刪除。😢
6.3.2 級聯刪除
級聯刪除是指當刪除一個記錄時,與之關聯的其他記錄也會被自動刪除。在 Django 中,可以通過設置外鍵的 on_delete
參數來實現級聯刪除。以下是一個級聯刪除的示例:
from django.db import models# 定義文章模型
class Article(models.Model):title = models.CharField(max_length=200)# 定義評論模型,與文章模型關聯
class Comment(models.Model):content = models.TextField()article = models.ForeignKey(Article, on_delete=models.CASCADE)
在這個示例中,Comment
模型通過外鍵 article
與 Article
模型關聯,并且設置了 on_delete=models.CASCADE
。這意味著當刪除一篇文章時,與之關聯的所有評論也會被自動刪除。🤯
通過以上介紹,我們了解了數據操作中創建數據、更新數據和刪除數據的常用方法,這些方法可以幫助我們更好地管理數據庫中的數據。🎉
第七章 高級特性
7.1 事務處理
7.1.1 事務的基本概念
1. 什么是事務
事務是數據庫管理系統執行過程中的一個邏輯單位,它由一組不可再分的數據庫操作序列組成,這些操作要么全部成功執行,要么全部不執行。就好比你去超市購物🛒,從挑選商品、結賬到離開超市,這一系列動作可以看作一個事務。如果結賬成功,那么整個購物過程就完成了;如果結賬時出現問題(比如錢不夠),那么之前挑選的商品也不會被買走,就好像什么都沒發生一樣。
2. 事務的特性(ACID)
- 原子性(Atomicity):事務中的所有操作要么全部完成,要么全部不完成,不會結束在中間某個環節。就像發射火箭🚀,一旦點火啟動,要么成功發射,要么發射失敗,不會出現發射到一半就停止的情況。
- 一致性(Consistency):事務執行前后,數據庫的狀態必須保持一致。例如,在銀行轉賬業務中,從一個賬戶向另一個賬戶轉賬,無論轉賬操作是否成功,兩個賬戶的總金額應該保持不變。
- 隔離性(Isolation):多個事務并發執行時,一個事務的執行不能被其他事務干擾。就好像在圖書館里,每個人都在自己的座位上安靜地看書📖,互不干擾。
- 持久性(Durability):事務一旦提交,它對數據庫的改變就是永久性的,即使數據庫發生故障也不會丟失。就像在紙上寫下的文字??,一旦寫上去,就很難抹去。
7.1.2 Django中的事務管理
1. Django事務管理的默認行為
在 Django 中,默認情況下,每個數據庫操作都是一個獨立的事務。也就是說,每個數據庫查詢都會自動提交。例如,當你執行一個 save()
方法保存一個模型實例時,這個操作會立即被提交到數據庫。
2. 手動管理事務
transaction.atomic()
:這是 Django 中用于管理事務的上下文管理器。使用它可以將一組數據庫操作封裝在一個事務中。例如:
from django.db import transactionwith transaction.atomic():# 一系列數據庫操作obj1.save()obj2.delete()
在這個例子中,obj1.save()
和 obj2.delete()
這兩個操作會被封裝在一個事務中。如果在執行過程中出現異常,整個事務會回滾,數據庫不會發生任何改變。
@transaction.atomic
裝飾器:如果你想將一個視圖函數或方法中的所有數據庫操作封裝在一個事務中,可以使用這個裝飾器。例如:
from django.db import transaction@transaction.atomic
def my_view(request):# 一系列數據庫操作...
7.2 自定義管理器
7.2.1 管理器的作用
1. 什么是管理器
在 Django 中,管理器是模型與數據庫交互的接口。每個 Django 模型都至少有一個管理器,默認情況下是 objects
管理器。它提供了一系列方法來查詢和操作數據庫中的數據。
2. 管理器的作用
- 提供自定義查詢方法:可以根據業務需求,為模型添加自定義的查詢方法。例如,如果你有一個
Book
模型,你可以添加一個get_popular_books()
方法來查詢所有受歡迎的書籍。 - 封裝業務邏輯:將一些與模型相關的業務邏輯封裝在管理器中,使代碼更加模塊化和可維護。例如,在創建新的
User
模型實例時,可以在管理器中添加一些初始化操作。
7.2.2 自定義管理器的創建
1. 創建自定義管理器類
要創建自定義管理器,需要繼承 django.db.models.Manager
類,并在其中定義自己的方法。例如:
from django.db import modelsclass BookManager(models.Manager):def get_popular_books(self):return self.filter(popularity__gt=100)class Book(models.Model):title = models.CharField(max_length=100)popularity = models.IntegerField()objects = BookManager()
在這個例子中,我們創建了一個 BookManager
類,它繼承自 models.Manager
類,并定義了一個 get_popular_books()
方法,用于查詢所有受歡迎的書籍(受歡迎程度大于 100)。然后,我們將 BookManager
實例賦值給 Book
模型的 objects
屬性,這樣就可以使用自定義的管理器了。
2. 使用自定義管理器
使用自定義管理器就像使用默認的 objects
管理器一樣。例如:
popular_books = Book.objects.get_popular_books()
7.3 原始SQL查詢
7.3.1 使用 raw()
方法
1. 什么是 raw()
方法
raw()
方法是 Django 提供的一個用于執行原始 SQL 查詢的方法。它允許你直接使用 SQL 語句來查詢數據庫,并將查詢結果封裝成模型實例。
2. 使用示例
假設我們有一個 Person
模型:
from django.db import modelsclass Person(models.Model):name = models.CharField(max_length=100)age = models.IntegerField()
我們可以使用 raw()
方法來執行原始 SQL 查詢:
people = Person.objects.raw('SELECT * FROM myapp_person WHERE age > 18')
for person in people:print(person.name)
在這個例子中,我們使用 raw()
方法執行了一個 SQL 查詢,查詢所有年齡大于 18 歲的人,并將查詢結果封裝成 Person
模型實例。
7.3.2 直接執行 SQL 語句
1. 使用 connection.cursor()
除了使用 raw()
方法,還可以使用 django.db.connection.cursor()
來直接執行 SQL 語句。例如:
from django.db import connectionwith connection.cursor() as cursor:cursor.execute('SELECT * FROM myapp_person WHERE age > 18')rows = cursor.fetchall()for row in rows:print(row)
在這個例子中,我們使用 connection.cursor()
創建了一個數據庫游標,然后使用 execute()
方法執行了一個 SQL 查詢,并使用 fetchall()
方法獲取查詢結果。
2. 注意事項
- SQL 注入風險:直接執行 SQL 語句時,要注意防止 SQL 注入攻擊。可以使用參數化查詢來避免這個問題。
- 數據庫兼容性:不同的數據庫系統可能對 SQL 語法有不同的支持,因此在編寫 SQL 語句時要考慮數據庫的兼容性。
第八章 性能優化
在開發過程中,性能優化是至關重要的,它可以顯著提升系統的響應速度和用戶體驗。接下來我們將詳細介紹查詢優化和數據庫優化兩方面的內容。
8.1 查詢優化
8.1.1 減少查詢次數
在進行數據庫操作時,頻繁的查詢會增加數據庫的負擔,降低系統性能。因此,我們要盡量減少不必要的查詢。
示例場景
假設我們要展示一個文章列表,每篇文章都有作者信息。如果我們在循環中每次都去查詢作者信息,就會產生大量的查詢。
# 不好的示例
articles = Article.objects.all()
for article in articles:author = Author.objects.get(id=article.author_id)print(f"文章: {article.title}, 作者: {author.name}")
在這個示例中,每遍歷一篇文章就會進行一次作者信息的查詢,如果有 100 篇文章,就會產生 100 次額外的查詢😫。
優化方法
我們可以通過一次查詢獲取所有需要的數據。
# 優化后的示例
articles = Article.objects.select_related('author').all()
for article in articles:print(f"文章: {article.title}, 作者: {article.author.name}")
這樣,我們只進行了一次查詢,就獲取了文章和作者的信息,大大減少了查詢次數👏。
8.1.2 使用 select_related() 和 prefetch_related()
1. select_related()
select_related()
主要用于處理一對一和外鍵關聯的查詢優化。它通過 SQL 的 JOIN
操作,在一次查詢中獲取相關聯的數據。
示例
# 假設 Book 模型有一個外鍵關聯到 Author 模型
books = Book.objects.select_related('author').all()
for book in books:print(f"書名: {book.title}, 作者: {book.author.name}")
在這個示例中,select_related('author')
會在查詢 Book
時,通過 JOIN
操作同時獲取 Author
的信息,避免了后續的額外查詢。
2. prefetch_related()
prefetch_related()
用于處理多對多和反向關聯的查詢優化。它會分別執行多個查詢,然后在 Python 層面進行關聯。
示例
# 假設 Book 模型有多對多關聯到 Tag 模型
books = Book.objects.prefetch_related('tags').all()
for book in books:for tag in book.tags.all():print(f"書名: {book.title}, 標簽: {tag.name}")
在這個示例中,prefetch_related('tags')
會先查詢所有的 Book
,再查詢所有相關的 Tag
,最后在 Python 中進行關聯,避免了在循環中多次查詢 Tag
。
8.2 數據庫優化
8.2.1 索引的使用
索引是數據庫中一種特殊的數據結構,它可以加快數據的查詢速度。就像書籍的目錄一樣,通過索引可以快速定位到所需的數據。
1. 何時使用索引
- 經常用于
WHERE
子句、JOIN
子句中的列。 - 經常用于排序的列。
2. 示例
假設我們有一個 User
模型,經常根據 username
進行查詢。
from django.db import modelsclass User(models.Model):username = models.CharField(max_length=100, db_index=True)email = models.EmailField()# 其他字段...
在這個示例中,db_index=True
表示為 username
字段創建索引。這樣,當我們根據 username
進行查詢時,數據庫可以更快地找到匹配的記錄。
3. 注意事項
- 索引會占用額外的存儲空間。
- 過多的索引會影響數據的插入、更新和刪除操作的性能,因為每次操作都需要更新索引。
8.2.2 數據庫配置優化
合理的數據庫配置可以提高數據庫的性能。以下是一些常見的配置優化建議:
1. 內存分配
根據服務器的內存情況,合理分配數據庫的內存。例如,對于 MySQL 數據庫,可以調整 innodb_buffer_pool_size
參數,它決定了 InnoDB 存儲引擎用于緩存數據和索引的內存大小。
2. 并發設置
調整數據庫的并發連接數,避免過多的連接導致數據庫性能下降。例如,對于 PostgreSQL 數據庫,可以通過 max_connections
參數來控制最大連接數。
3. 日志配置
合理配置數據庫的日志,避免日志記錄過多影響性能。例如,對于 MySQL 數據庫,可以根據實際情況調整 log_bin
(二進制日志)和 slow_query_log
(慢查詢日志)的相關參數。
通過以上的查詢優化和數據庫優化方法,可以顯著提升系統的性能,讓你的應用更加流暢😃。
第九章 測試與調試
9.1 單元測試
9.1.1 測試框架的選擇
在進行單元測試時,選擇合適的測試框架至關重要,它能幫助我們更高效地編寫和運行測試用例。以下為你介紹幾種常見的測試框架😃:
1. unittest(Python 內置)
- 特點:是 Python 標準庫的一部分,無需額外安裝,提供了基礎的測試功能,如測試用例的組織、斷言方法等。它遵循面向對象的設計,使用起來比較規范。
- 適用場景:適合初學者入門,以及對項目依賴要求較低的場景。例如,小型 Python 腳本的單元測試。
- 示例代碼:
import unittestdef add(a, b):return a + bclass TestAdd(unittest.TestCase):def test_add(self):result = add(2, 3)self.assertEqual(result, 5)if __name__ == '__main__':unittest.main()
2. pytest
- 特點:功能強大,語法簡潔,支持參數化測試、fixture 等高級特性,能自動發現測試用例,并且有豐富的插件生態系統。
- 適用場景:適用于各種規模的項目,尤其是需要進行復雜測試的場景。例如,大型 Web 應用的單元測試。
- 示例代碼:
def add(a, b):return a + bdef test_add():assert add(2, 3) == 5
3. Jasmine(JavaScript)
- 特點:是一個行為驅動開發(BDD)的測試框架,無需外部依賴,自帶斷言庫和測試運行器,適合測試 JavaScript 代碼。
- 適用場景:常用于前端 JavaScript 代碼的單元測試,如網頁中的腳本。
- 示例代碼:
function add(a, b) {return a + b;
}describe('add function', function() {it('should return the sum of two numbers', function() {expect(add(2, 3)).toBe(5);});
});
9.1.2 編寫測試用例
編寫高質量的測試用例是單元測試的核心,以下是編寫測試用例的步驟和要點🧐:
1. 明確測試目標
在編寫測試用例之前,需要明確要測試的功能或方法,確定其輸入和預期輸出。例如,要測試一個函數 calculate_average
,它接收一個數字列表作為輸入,返回這些數字的平均值。
2. 選擇合適的測試數據
- 正常數據:選擇符合函數預期輸入的數據進行測試。例如,對于
calculate_average
函數,可以使用[1, 2, 3]
作為測試數據。 - 邊界數據:考慮輸入的邊界情況,如空列表、只有一個元素的列表等。對于
calculate_average
函數,空列表是一個邊界情況。 - 異常數據:測試函數在遇到異常輸入時的處理能力。例如,傳入非數字列表。
3. 使用斷言
斷言是測試用例中用于驗證實際輸出是否符合預期輸出的語句。不同的測試框架提供了不同的斷言方法,如 unittest
中的 assertEqual
,pytest
中的 assert
,Jasmine
中的 expect
。
4. 示例代碼
以下是使用 pytest
為 calculate_average
函數編寫的測試用例:
def calculate_average(numbers):if not numbers:return 0return sum(numbers) / len(numbers)def test_calculate_average_normal():numbers = [1, 2, 3]result = calculate_average(numbers)assert result == 2def test_calculate_average_empty():numbers = []result = calculate_average(numbers)assert result == 0
9.2 調試技巧
9.2.1 使用 Django 調試工具
Django 提供了一些強大的調試工具,能幫助我們快速定位和解決問題😎:
1. DEBUG 模式
- 開啟方法:在
settings.py
文件中,將DEBUG
設置為True
。
DEBUG = True
- 作用:當應用出現錯誤時,Django 會顯示詳細的錯誤頁面,包含錯誤類型、錯誤堆棧信息、請求信息等,方便我們定位問題。
2. Django Debug Toolbar
- 安裝方法:使用
pip install django-debug-toolbar
進行安裝,然后在settings.py
中進行配置。
INSTALLED_APPS = [# ...'debug_toolbar',# ...
]MIDDLEWARE = [# ...'debug_toolbar.middleware.DebugToolbarMiddleware',# ...
]INTERNAL_IPS = ['127.0.0.1',
]
- 作用:在開發環境中,它會在頁面右側顯示一個工具欄,提供了 SQL 查詢、模板渲染、請求信息等詳細信息,幫助我們優化代碼性能。
3. 日志記錄
可以在 settings.py
中配置日志記錄,將關鍵信息記錄到日志文件中,方便后續分析。
LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'file': {'level': 'DEBUG','class': 'logging.FileHandler','filename': 'debug.log',},},'loggers': {'django': {'handlers': ['file'],'level': 'DEBUG','propagate': True,},},
}
9.2.2 日志記錄
日志記錄是調試過程中非常重要的一環,它可以幫助我們記錄程序的運行狀態和關鍵信息📝:
1. 日志級別
常見的日志級別有 DEBUG
、INFO
、WARNING
、ERROR
、CRITICAL
,從低到高表示不同的嚴重程度。
2. 配置日志
在 Python 中,可以使用內置的 logging
模塊進行日志配置。以下是一個簡單的配置示例:
import logging# 配置日志
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(levelname)s - %(message)s',filename='app.log'
)# 記錄日志
logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')
3. 日志的使用場景
- DEBUG 級別:用于開發和調試階段,記錄詳細的程序運行信息。
- INFO 級別:記錄程序的正常運行狀態,如用戶登錄、數據更新等。
- WARNING 級別:表示可能存在問題,但不影響程序的正常運行,如文件讀取失敗但有默認值。
- ERROR 級別:記錄程序中出現的錯誤,如數據庫連接失敗。
- CRITICAL 級別:表示嚴重的錯誤,可能導致程序無法繼續運行,如系統崩潰。