ORM
Object-Relational Mapping
對應關系
ORM DB
類 資料表
對象 資料行
屬性 字段
ORM提高開發效率,降低了執行效率
Flask- Sqlalchemy
字段類型和參數
1、字段類型
# 自增長 預設int
Auto = models.AutoField(primary_key=True)
BigAuto = models.BigAutoField()
# 二進制
Binary = models.BinaryField()
# 布爾
Boolean = models.BooleanField()
NullBoolean = models.NullBooleanField()
# 整型
PositiveSmallInteger = models.PositiveSmallIntegerField() # 5位元組
SmallInteger = models.SmallIntegerField() # 6位元組
PositiveInteger = models.PositiveIntegerField() # 10位元組
Integer = models.IntegerField() # 11位元組
BigInteger = models.BigIntegerField() # 20位元組
# 字元串
Char = models.CharField() # varchar
Text = models.TextField() # longtext
# 時間日期
Date = models.DateField()
DateTime = models.DateTimeField()
Duration = models.DurationField() # int python timedelta實作
# 浮點型
Float = models.FloatField()
Decimal = models.DecimalField()
# 其他
Email = models.EmailField() # 郵箱
Image = models.ImageField()
File = models.FileField()
FilePath = models.FilePathField()
URL = models.URLField()
UUID = models.UUIDField()
GenericIPAddress = models.GenericIPAddressField()
2、關系型字段
一對一 OneToOneField
多對一 ForeignKey
多對對 ManyToManyField 預設或自定義中間表
3、字段類型參數
預設表名
應用_模型類名小寫
eg: app_student
(1)所有字段都有的參數
db_column="name" 指定資料庫字段名
verbose_name="别名"
help_text="表單說明"
primary_key=True 設定主鍵
unique=True 唯一鍵
null=True 資料庫允許為空,預設都是不能為null的
blank=True 前端送出表單允許為空
db_index=True 建立索引
editable=False 不允許編輯字段
(2)個别字段的參數
CharField
max_length=100 最大長度
DateField、DateTime
unique_for_date=True 日期必須唯一
unique_for_month=True 月份唯一
auto_now=True 自動更新記錄時間
auto_now_add=True 自動增加記錄時間
DecimalField
max_digits=4 總位數
decimal_places=2 小數點數
eg: 11.22 16.34
(3)關系型字段參數
OneToOneField
related_name="one" 父表查字表資料
ForeignKey
on_delete="" 外鍵所關聯的對象被删除時進行的操作
CASCADE: 級聯删除。将定義有外鍵的模型對象同時删除, 預設操作
PROTECT: 阻止删除。會報完整性錯誤。
DO_NOTHING:什麼也不做
SET_NULL:外鍵設定為 null,前提是 null=True, blank=True。
SET_DEFAULT:設定為外鍵的預設值,前提是設定了default參數。
SET():會調用外面的值,可以是一個函數。一般情況下使用 CASCADE 就可以了。
eg:
```python
class B(models.Model):
foreign = models.ForeignKey(A, on_delete=models.CASCADE)
foreign = models.ForeignKey(A, on_delete=models.PROTECT)
foreign = models.ForeignKey(A, on_delete=models.DO_NOTHING)
foreign = models.ForeignKey(A, on_delete=models.SET_NULL, null=True, blank=True)
foreign = models.ForeignKey(A, on_delete=models.SET_DEFAULT, default=0)
foreign = models.ForeignKey(A, on_delete=models.SET)
4、自關聯
示例:位址 省-市-縣 級聯
class AddressInfo(models.Model):
address = models.CharField(max_length=200, null=True, blank=True, verbose_name="位址")
pid = models.ForeignKey("self", null=True, blank=True, verbose_name="自關聯", on_delete=models.SET_NULL)
def __str__(self):
return self.address
中繼資料Meta
修改應用名稱
apps.py
class OrmdemoConfig(AppConfig):
name = 'ormdemo'
verbose_name = "應用名稱"
修改model中繼資料
class AddressInfo(models.Model):
address = models.CharField(max_length=200, null=True, blank=True, verbose_name="位址")
note = models.CharField(max_length=200, null=True, blank=True, verbose_name="說明")
pid = models.ForeignKey("self", null=True, blank=True, verbose_name="自關聯", on_delete=models.SET_NULL)
def __str__(self):
return self.address
class Meta:
db_table = "address" # 自定義表名
ordering = ["pid_id"] # 指定排序字段
verbose_name = "位址" # 單數
verbose_name_plural = verbose_name # 複數
abstract = True # 設定為基類
permissions = (("定義好的權限", "權限說明"),)
managed = False # 按照Django預設方式管理資料表
unique_together = ("address", "note") # 聯合唯一鍵,單元組或多元組
app_label = "ormdemo" # 定義模型類屬于哪個應用
db_tablespace = "" # 定義資料庫表空間
模型類開發執行個體

"""
講師 - 助教 一對一
講師 - 課程表 一對多
課程表 - 學生 多對多
"""
class Teacher(models.Model):
"""講師資訊表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵稱")
introduction = models.TextField(default="這位同學很懶,木有簽名的說~", verbose_name="簡介")
fans = models.PositiveIntegerField(default=0, verbose_name="粉絲數")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="建立時間")
updated_at = models.DateTimeField(auto_now=True, verbose_name="建立時間")
class Meta:
verbose_name = "講師資訊表"
verbose_name_plural = verbose_name
def __str__(self):
return self.nickname
class Course(models.Model):
"""課程資訊表"""
title = models.CharField(max_length=100, primary_key=True, db_index=True, verbose_name="課程名")
type = models.CharField(choices=((0, "其他"), (1, "實戰課"), (2, "免費課")), max_length=1, default=0, verbose_name="課程類型")
price = models.PositiveSmallIntegerField(verbose_name="價格")
volume = models.BigIntegerField(verbose_name="銷量")
online = models.DateField(verbose_name="上線時間")
# 删除級聯
teacher = models.ForeignKey(Teacher, null=True, blank=True, on_delete=models.CASCADE, verbose_name="講師")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="建立時間")
updated_at = models.DateTimeField(auto_now=True, verbose_name="建立時間")
class Meta:
verbose_name = "課程資訊表"
verbose_name_plural = verbose_name
def __str__(self):
return f"{self.get_type_display()}-{self.title}"
class Student(models.Model):
"""學生資訊表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="學生姓名")
age = models.PositiveSmallIntegerField(verbose_name="年齡")
gender = models.CharField(choices=((0, "保密"), (1, "男"), (2, "女")), max_length=1, default=0, verbose_name="性别")
study_time = models.PositiveIntegerField(default=0, verbose_name="學習時長(h)")
course = models.ManyToManyField(Course, verbose_name="課程")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="建立時間")
updated_at = models.DateTimeField(auto_now=True, verbose_name="建立時間")
class Meta:
verbose_name = "學生資訊表"
verbose_name_plural = verbose_name
def __str__(self):
return self.nickname
class TeacherAssistant(models.Model):
"""助教資訊表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵稱")
hobby = models.CharField(max_length=10, null=True, blank=True, verbose_name="愛好")
# 删除置空
teacher = models.OneToOneField(Teacher, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="講師")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="建立時間")
updated_at = models.DateTimeField(auto_now=True, verbose_name="建立時間")
class Meta:
verbose_name = "助教資訊表"
verbose_name_plural = verbose_name
def __str__(self):
return self.nickname
生成資料表
python manage.py makemigrations # 生成遷移檔案
python manage.py migrate # 執行遷移檔案
删除某個模型類的完整操作:
(1)在已建立的app下, 首先删除models.py中需要删除的模型類
(2)删除該模型類在遷移腳本migrations中的對應檔案
(3)删除該項目在django_migrations中的對應記錄
(4)删除資料庫中對應的資料表
導入資料
(1)django shell
$ python manage.py shell
from app.models import Mode
model = Model()
model.name = "name"
model.save()
(2)腳本導入
# -*- coding: utf-8 -*-
import os
import random
from datetime import date
import django
import sys
# 導入項目配置
project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_path)
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
django.setup()
from ormdemo.models import Teacher, Course, Student, TeacherAssistant
def import_data():
# 講師資料 create
Teacher.objects.create(nickname="Jack", introduction="Python工程師", fans=666)
# 課程資料 bulk_create
data = [
Course(title=f"Python系列教程{i}",
teacher=Teacher.objects.get(nickname="Jack"),
type=random.choice([0, 1, 2]),
price=random.randint(200, 300),
volume=random.randint(100, 10000),
online=date(2018, 10, 1)
)
for i in range(1, 5)
]
Course.objects.bulk_create(data)
# 學生資料 update_or_create
Student.objects.update_or_create(
nickname="A同學",
defaults={
"age": random.randint(18, 58),
"gender": random.choice([0, 1, 2]),
"study_time": random.randint(9, 999)
}
)
# 正向添加
# 銷量大于等于1000的課程
Student.objects.get(nickname="A同學").course.add(*Course.objects.filter(volume__gte=1000))
# 反向添加
# 學習時間大于等于500小時的同學
Course.objects.get(title="Python系列教程1").student_set.add(*Student.objects.filter(
study_time__gte=500
))
# 助教資料 get_or_create()
TeacherAssistant.objects.get_or_create(
nickname="助教1",
defaults={
"hobby": "慕課網學習",
"teacher": Teacher.objects.get(nickname="Jack")
}
)
if __name__ == '__main__':
import_data()
(3)fixtures
Django serialization -> model儲存
python manage.py dumpdata > data.json # 導出資料
python manage.py loaddata data.json # 導入資料
(4)mysqldump
MySQL資料庫導入導出資料
(5)PyCharm
PyCharm自帶的導入導出工具
ModelAPI
1、查詢,檢索,過濾
Teacher.objects.all() # 傳回多個結果
Teacher.objects.get(id=1) 傳回一條結果
Teacher.objects.filter(fans__gte=500) # 傳回多個結果
2、資料比對大小寫敏感
# 雙下劃線開頭`__`
Teacher.objects.filter(fans__in=[500, 600])
# i開頭表示大小寫敏感
Teacher.objects.filter(nickname__icontains="A")
3、結果切片、排序、鍊式查詢
Teacher.objects.all()[:1]
Teacher.objects.all().order_by("-age") # 負号表示降序
Teacher.objects.filter(fans__gte=500).order_by("nickname") # 查詢集可以繼續使用排序
4、檢視執行的原生SQL
Teacher.objects.all().order_by("-nickname").query
"""
SELECT `ormdemo_teacher`.`nickname`,
FROM `ormdemo_teacher`
ORDER BY `ormdemo_teacher`.`nickname` DESC
"""
傳回新的QuerySet的API
讀操作大部分都傳回
1、第一類
all 全部
filter 過濾
order_by 排序
exclude 排除
reverse 逆序 需要在中繼資料中設定ordering
distinct 去重
Student.objects.all().exclude(nickname="A同學")
# SELECT `ormdemo_student`.`nickname`
# FROM `ormdemo_student`
# WHERE NOT (`ormdemo_student`.`nickname` = A同學)
Student.objects.all().exclude(nickname="A同學").reverse()
"""
ELECT `ormdemo_student`.`nickname`
FROM `ormdemo_student`
WHERE NOT (`ormdemo_student`.`nickname` = A同學)
"""
2、第二類
extra 别名
defer 排除一些字段
only 選擇一些字段
Student.objects.all().extra(select={"name": "nickname"})
"""
SELECT (nickname) AS `name`, `ormdemo_student`.`nickname`, `ormdemo_student`.`age`
FROM `ormdemo_student`
"""
Student.objects.all().only("nickname", "age")
"""
SELECT `ormdemo_student`.`nickname`, `ormdemo_student`.`age` FROM `ormdemo_student`
"""
3、第三類
values 擷取字典形式
values_list 擷取元組形式
Student.objects.values("nickname", "age")
# <QuerySet [{'nickname': 'A同學', 'age': 54}, {'nickname': 'B同學', 'age': 36}]>
Student.objects.values_list("nickname", "age")
# <QuerySet [('A同學', 54), ('B同學', 36)]>
Student.objects.values_list("nickname", flat=True) # 單個字段傳回清單
# <QuerySet ['A同學', 'B同學']>
4、第四類
dates、datatimes根據時間日期擷取查詢集
Student.objects.dates("created_at", "month")
"""
SELECT DISTINCT CAST(DATE_FORMAT(`ormdemo_student`.`created_at`, '%Y-%m-01') AS DATE) AS `datefield`
FROM `ormdemo_student`
WHERE `ormdemo_student`.`created_at` IS NOT NULL
ORDER BY `datefield` ASC
"""
5、第五類
union 并集
intersection 交集 需要資料庫支援
difference 差集 需要資料庫支援
ret1 = Student.objects.filter(nickname="同學A")
ret2 = Student.objects.filter(nickname="同學B")
ret1.union(ret2)
"""
(SELECT `ormdemo_student`.`nickname
FROM `ormdemo_student`
WHERE `ormdemo_student`.`nickname` = '同學A')
UNION
(SELECT `ormdemo_student`.`nickname`
FROM `ormdemo_student`
WHERE `ormdemo_student`.`nickname` = '同學B')
LIMIT 2
6、第六類
select_related 一對一,多對一查詢優化
prefetch_related 一對多,多對多查詢優化
Course.objects.all().select_related("teacher")
"""
SELECT `ormdemo_course`.`title`, `ormdemo_teacher`.`nickname`
FROM `ormdemo_course`
LEFT OUTER JOIN `ormdemo_teacher`
ON (`ormdemo_course`.`teacher_id` = `ormdemo_teacher`.`nickname`)
LIMIT 21;
"""
Student.objects.all().prefetch_related("course")
"""
SELECT `ormdemo_student`.`nickname`
FROM `ormdemo_student` LIMIT 21;
SELECT (`ormdemo_student_course`.`student_id`) AS `_prefetch_related_val_student_id`, `ormdemo_course`.`title`
FROM `ormdemo_course`
INNER JOIN `ormdemo_student_course`
ON (`ormdemo_course`.`title` = `ormdemo_student_course`.`course_id`)
WHERE `ormdemo_student_course`.`student_id` IN ('A同學', 'B同學', 'C同學', 'D同學');
"""
反向查詢
Teacher.objects.get(nickname="Jack").course_set.all()
"""
SELECT `ormdemo_teacher`.`nickname`
FROM `ormdemo_teacher`
WHERE `ormdemo_teacher`.`nickname` = 'Jack'
SELECT `ormdemo_course`.`title`
FROM `ormdemo_course`
WHERE `ormdemo_course`.`teacher_id` = 'Jack'
LIMIT 21;
"""
7、第七類
annotate 聚合計數,求和,平均數,執行原生SQL(分組後的資料進行統計)
from django.db.models import Count, Avg, Max, Min, Sum
Course.objects.values("teacher").annotate(vol=Sum("volume"))
"""
SELECT `ormdemo_course`.`teacher_id`, SUM(`ormdemo_course`.`volume`) AS `vol`
FROM `ormdemo_course`
GROUP BY `ormdemo_course`.`teacher_id`
ORDER BY NULL LIMIT 21;
"""
Course.objects.values("teacher").annotate(pri=Avg("price"))
"""
SELECT `ormdemo_course`.`teacher_id`, AVG(`ormdemo_course`.`price`) AS `pri`
FROM `ormdemo_course`
GROUP BY `ormdemo_course`.`teacher_id`
ORDER BY NULL LIMIT 21;
# order by null用途是強制對查詢結果禁用排序
"""
不傳回QuerySet的API
寫操作都不傳回結果集
1、擷取對象
get, get_or_create, first, last, in_bulk
latest最近記錄, earliest 最早記錄 需要設定中繼資料get_latest_by
Student.objects.get(nickname="A同學") # 傳回多個會報錯
"""
SELECT `ormdemo_student`.`nickname`
FROM `ormdemo_student`
WHERE `ormdemo_student`.`nickname` = 'A同學'
"""
Student.objects.first()
"""
SELECT `ormdemo_student`.`nickname`
FROM `ormdemo_student`
ORDER BY `ormdemo_student`.`nickname` ASC
LIMIT 1
"""
Student.objects.last()
"""
SELECT `ormdemo_student`.`nickname`
FROM `ormdemo_student`
ORDER BY `ormdemo_student`.`nickname` DESC
LIMIT 1;
"""
Student.objects.in_bulk(["A同學"])
"""
SELECT `ormdemo_student`.`nickname`
FROM `ormdemo_student`
WHERE `ormdemo_student`.`nickname` IN ('A同學');
"""
Student.objects.latest()
"""
SELECT `ormdemo_student`.`nickname
FROM `ormdemo_student`
ORDER BY `ormdemo_student`.`created_at` DESC
LIMIT 1;
"""
Student.objects.earliest()
"""
SELECT `ormdemo_student`.`nickname
FROM `ormdemo_student`
ORDER BY `ormdemo_student`.`created_at` ASC
LIMIT 1;
2、建立對象
create, bulk_create, update_or_create
3、更新對象
update, update_or_create
Student.objects.filter(nickname="A同學").update(age=13)
"""
UPDATE `ormdemo_student`
SET `age` = 13
WHERE `ormdemo_student`.`nickname` = 'A同學';
"""
4、删除對象
delete 使用filter過濾
Student.objects.filter(nickname="A同學").delete()
"""
SELECT `ormdemo_student`.`nickname
FROM `ormdemo_student`
WHERE `ormdemo_student`.`nickname` = 'A同學';
DELETE FROM `ormdemo_student_course`
WHERE `ormdemo_student_course`.`student_id` IN ('A同學');
DELETE FROM `ormdemo_student`
WHERE `ormdemo_student`.`nickname` IN ('A同學');
(13, {'ormdemo.Student_course': 12, 'ormdemo.Student': 1})
"""
5、其他操作
exists, count, aggregate(整個資料表統計)
Student.objects.filter(nickname="B同學").exists()
"""
SELECT (1) AS `a`
FROM `ormdemo_student`
WHERE `ormdemo_student`.`nickname` = 'B同學'
LIMIT 1
"""
Student.objects.filter(nickname="B同學").count()
"""
SELECT COUNT(*) AS `__count`
FROM `ormdemo_student`
WHERE `ormdemo_student`.`nickname` = 'B同學';
"""
Course.objects.aggregate(Max("price"), Min("price"), Avg("price"), Sum("volum"))
"""
SELECT
MAX(`ormdemo_course`.`price`) AS `price__max`,
MIN(`ormdemo_course`.`price`) AS `price__min`,
AVG(`ormdemo_course`.`price`) AS `price__avg`,
SUM(`ormdemo_course`.`volume`) AS `volume__sum`
FROM `ormdemo_course`;
{'price__max': 295, 'price__min': 210, 'price__avg': 250.75, 'volume__sum': 60559}
"""
自定義聚合查詢(略)
group_contact
F對象和Q對象
F對象 操作字段資料
Q對象 結合AND OR NOT | ~ & 實作複雜查詢
from django.db.models import F, Q
Student.objects.update(age=F("age") + 3)
"""
UPDATE `ormdemo_student` SET `age` = (`ormdemo_student`.`age` + 3);
"""
Student.objects.filter(Q(age__gte=1) & Q(age__lte=10))
"""
SELECT `ormdemo_student`.`nickname`
FROM `ormdemo_student`
WHERE (`ormdemo_student`.`age` >= 1 AND `ormdemo_student`.`age` <= 10)
LIMIT 21;
"""