概述:Django對各種數(shù)據(jù)庫都提供了很好的支持,Django為這些數(shù)據(jù)庫提供了統(tǒng)一的調用接口API,程序員可以根據(jù)自己的業(yè)務需求選擇不同的數(shù)據(jù)庫
ORM簡介
概述:對象-關系-映射
作用: 根據(jù)類生成表結構;將對象、列表的操作轉換成對應的SQL語句;將SQL語句查詢到的結果轉換為對象或者列表
優(yōu)點:極大的減輕開發(fā)人員的工作量,不需要面對因數(shù)據(jù)庫的變更而導致代碼無效在修改代碼, 防止sql注入攻擊
圖解:

模型、屬性、表、字段之間的關系:一個模型在數(shù)據(jù)庫中對應一張表,在模型中定義的屬性對應該模型對照表中的一個字段
創(chuàng)建模型類
班級類
class Grade(models.Model):
name = models.CharField(max_length=20)
boyNum = models.IntegerField()
girlNum = models.IntegerField()
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
學生類
class Student(models.Model):
name = models.CharField(max_length=20)
sex = models.BooleanField()
age = models.IntegerField()
contend = models.CharField(max_length=40)
# 關聯(lián)類名的小寫或直接類名 Grade
grade = models.ForeignKey("grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
字段類型和字段選項
字段類型
·AutoField
·一個根據(jù)實際ID自動增長的IntegerField,通常不指定如果不指定,一個主鍵字段將自動添加到模型中
·CharField(max_length=字符長度)
·字符串,默認的表單樣式是 TextInput
·TextField
·大文本字段,一般超過4000使用,默認的表單控件是Textarea
·IntegerField
·整數(shù)
·DecimalField(max_digits=None, decimal_places=None)
·使用python的Decimal實例表示的十進制浮點數(shù)
·參數(shù)說明
·DecimalField.max_digits
·位數(shù)總數(shù)
·DecimalField.decimal_places
·小數(shù)點后的數(shù)字位數(shù)
·FloatField
·用Python的float實例來表示的浮點數(shù)
·BooleanField
·true/false 字段,此字段的默認表單控制是CheckboxInput
·NullBooleanField
·支持null、true、false三種值
·DateField(auto_now=False, auto_now_add=False)
·使用Python的datetime.date實例表示的日期
·參數(shù)說明
·DateField.auto_now
·每次保存對象時,自動設置該字段為當前時間,用于"最后一次修改"的時間戳,它總是使用當前日期, 默認為false
·DateField.auto_now_add
·當對象第一次被創(chuàng)建時自動設置當前時間,用于創(chuàng)建的時間戳,它總是使用當前日期,默認為false
·說明
·該字段默認對應的表單控件是一個TextInput. 在管理員站點添加了一個JavaScript寫的日歷控件,和一 個“Today"的快捷按鈕,包含了一個額外的invalid_date錯誤消息鍵
·注意
·auto_now_add, auto_now, and default 這些設置是相互排斥的,他們之間的任何組合會發(fā)生錯誤的結果
·TimeField
·使用Python的datetime.time實例表示的時間,參數(shù)同DateField
·DateTimeField
·使用Python的datetime.datetime實例表示的日期和時間,參數(shù)同DateField
·FileField
·一個上傳文件的字段
·ImageField
·繼承了FileField的所有屬性和方法,但對上傳的對象進行校驗,確保它是個有效的image
字段選項
·概述
·通過字段選項,可以實現(xiàn)對字段的約束
·在字段對象時通過關鍵字參數(shù)指定
·null
·如果為True,Django 將空值以NULL存儲到數(shù)據(jù)庫中,默認值是 False
·blank
·如果為True,則該字段允許為空白,默認值是 False
·注意
·null是數(shù)據(jù)庫范疇的概念,blank是表單驗證證范疇的
·db_column
·字段的名稱,如果未指定,則使用屬性的名稱
·db_index
·若值為 True, 則在表中會為此字段創(chuàng)建索引
·default
·默認值
·primary_key
·若為 True, 則該字段會成為模型的主鍵字段
·unique
·如果為 True, 這個字段在表中必須有唯一值
模型之間的關系
模型關系
·分類
·ForeignKey:一對多,將字段定義在多的端中
·ManyToManyField:多對多,將字段定義在兩端中
·OneToOneField:一對一,將字段定義在任意一端中
·用一訪問多
·格式
對象.模型類小寫_set
·示例
grade.students_set
·用一訪問一
·格式
·對象.模型類小寫
·示例
·grade.students
·訪問id
·格式
·對象.屬性_id
·示例
·student.sgrade_id
元選項
在模型類中定義一個Meta類,用于設置元信息
class Student(models.Model):
name = models.CharField(max_length=20)
sex = models.BooleanField()
age = models.IntegerField()
contend = models.CharField(max_length=40)
# 關聯(lián)類名的小寫
grade = models.ForeignKey("grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta():
db_table = "students"
ordering = ["-id"]
屬性
- db_table: 定義數(shù)據(jù)表名,推薦使用類名小寫,并且添加復數(shù)
- ordering: 規(guī)定對象的默認排序字段 ; ordering = ["id"]: 正序; ordering = ["-id"]: 倒序;
注意:排序會增加數(shù)據(jù)庫的開銷
模型成員
objects對象
概述: 是Manager類型的對象,用于與數(shù)據(jù)庫進行交互; 當定義模型時沒有指定管理器,則Django會為模型提供一個名為objects的管理器
自定義模型管理器
class Student(models.Model):
#自定義模型管理器
myobject = models.Manager()
name = models.CharField(max_length=20)
sex = models.BooleanField()
age = models.IntegerField()
contend = models.CharField(max_length=40)
# 關聯(lián)類名的小寫
grade = models.ForeignKey("grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta():
db_table = "students"
ordering = ["-id"]
注意: 如果為模型指定了管理器,那么Django不再為模型類提供名為objects的管理器
自定義模型管理器類
class StudentManager(models.Manager):
def get_queryset(self):
return super(StudentManager, self).get_queryset().filter(isDelete=False)
class Student(models.Model):
#自定義模型管理器
objects = StudentManager()
get_queryset獲取查詢集(數(shù)據(jù)集),自定義管理器類調用父類中的get_queryset方法后在進行過濾
創(chuàng)建對象
當創(chuàng)建對象時,Django不會對數(shù)據(jù)庫進行讀寫操作。調用save()方法才與數(shù)據(jù)庫進行交互,將對象存儲到數(shù)據(jù)庫中。init方法已經(jīng)在基類models.Model中使用,在自定義模型類中無法使用
在模型類中增加一個類方法:
class Student(models.Model):
#自定義模型管理器
objects = StudentManager()
name = models.CharField(max_length=20)
sex = models.BooleanField()
age = models.IntegerField()
contend = models.CharField(max_length=40)
grade = models.ForeignKey(Grade)
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta():
db_table = "students"
ordering = ["-id"]
#類方法,類可以直接調用 創(chuàng)建對象可以直接寫 Student.create('ray',1,18,....)
@classmethod
def create(cls, name, sex, age, contend, grade):
return cls(name=name, sex=sex, age=age, contend=contend, grade=grade)
在自定義模型器類中增加一個方法
class StudentManager(models.Manager):
def get_queryset(self):
return super(StudentManager, self).get_queryset().filter(isDelete=False)
def create(self, name, sex, age, contend, grade):
obj = self.model()
obj.name = name
obj.sex = sex
obj.age = age
obj.contend = contend
obj.grade = grade
return obj
查詢數(shù)據(jù)
查詢集:表示從數(shù)據(jù)庫中獲取的對象集合,查詢集可以含有一個或者多個過濾器
過濾器:基于所給的參數(shù)限制查詢集的結果,得到新的查詢集
從SQL的角度,查詢集合select語句等價,過濾器就像where和limit子句相似
查詢集
在管理器上調用過濾器方法或者是其他數(shù)據(jù)查詢集上調用過濾器方法得到新的查詢集
查詢集經(jīng)過過濾器篩選得到新的查詢集,因此可以使用鏈式語法結構
惰性查詢:創(chuàng)建查詢集不會帶來任何的數(shù)據(jù)庫訪問,直到調用數(shù)據(jù)時,才會訪問數(shù)據(jù)庫
什么時候對查詢集求值? 迭代、序列化、與if合用
返回查詢集的方法
all()
返回查詢集的方法
def students(request):
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
filter()
作用:將符合條件的數(shù)據(jù)過濾進來
使用:filter(鍵1=值1, 鍵2=值2);filter(鍵1=值1, 鍵2=值2)
def students(request):
stus = Student.objects.filter(age=20)
return render(request, 'students.html', {"stus":stus})
exclude()
作用: 將符合條件的數(shù)據(jù)過濾出去
def students(request):
stus = Student.objects.exclude(age=20)
return render(request, 'students.html', {"stus":stus})
order_by()
作用:排序
def students(request):
stus = Student.objects.order_by("age")
return render(request, 'students.html', {"stus":stus})
def students(request):
stus = Student.objects.order_by("-age")
return render(request, 'students.html', {"stus":stus})
values()
作用: 一個對象構成一個字典,然后構成一個列表返回
def students(request):
stus = Student.objects.values()
print(stus)
return render(request, 'students.html', {"stus":stus})
返回單個值的方法
get()
作用: 返回單個滿足條件的對象
def students(request):
# pk代表主鍵
try:
stus = [Student.objects.get(age=20)]
except Student.DoesNotExist as e:
pass
except Student.MultipleObjectsReturned as e:
pass
return render(request, 'students.html', {"stus":stus})
注意: 如果多條數(shù)據(jù)被返回,會引發(fā) “類名.MultipleObjectsReturned” 異常;數(shù)據(jù)不存在會報 "類名.DoesNotExist" 異常
count()
返回當前查詢的總條數(shù)
first()
返回查詢集中的第一個對象
last()
返回查詢集中的最后一個對象
exists()
判斷查詢集中是否有數(shù)據(jù),如果有返回True,否則返回False
def students(request):
stus = Student.objects.filter(age=20)
if stus.exists():
return render(request, 'students.html', {"stus":stus})
else:
return HttpResponse("沒有學生數(shù)據(jù)")
限制查詢集
查詢集返回列表,可以使用下標的方式進行限制,等同于SQL中的limit和offset子句
注意: 不支持負數(shù)索引; 使用下標后返回一個新的查詢集,不會立即執(zhí)行查詢字段查詢
def students(request):
stus = Student.objects.all()[5:10]#[0:5)
return render(request, 'students.html', {"stus":stus})
字段查詢
概述
實現(xiàn)where語句,作為filter()、exclude()、get()的參數(shù)
語法 : 屬性名稱__比較運算符=值 (注意:里面有兩個下劃線)
外鍵: 使用 “屬性名_id” 表示原始的外鍵值
轉義: like語句中使用%,可以直接使用
比較運算符
exact: 表示判斷相當,大小寫敏感
contains: 是否包含,大小寫敏感
# 找描述中帶有"ray"的所有學生
def students(request):
stus = Student.objects.filter(contend__icontains="sunck")
return render(request, 'students.html', {"stus":stus})
startswith、endswith: 以value開頭、結尾,大小寫敏感
# 找描述以ray開頭的所有學生
def students(request):
stus = Student.objects.filter(contend__startswith="ray")
return render(request, 'students.html', {"stus":stus})
iexact、icontains、istartswith、iendswith: 不區(qū)分大小寫
isnull, isnotnull : 是否為空, 是否為非空
in : 包含在范圍之內
# 找id為2,5,8,9的學生
def students(request):
stus = Student.objects.filter(pk__in=[2,5,8,9])
return render(request, 'students.html', {"stus":stus})
gt, gte, lt, lte
# 找年齡大于等于20的所有學生
def students(request):
stus = Student.objects.filter(age__gte=20)
return render(request, 'students.html', {"stus":stus})
year、month、day、week_day、hour、minute、second: 對日期類型的屬性進行運算
跨關聯(lián)關系的查詢
處理join查詢:
語法:關聯(lián)的模型類名小寫_屬性名_比較運算符=值
注意: __比較運算符 沒有,表示等于; 可以反向使用,即關聯(lián)的兩個模型中都可以使用
# 描述中帶有ray的學生屬于那些班級
def students(request):
grades = Grade.objects.filter(student__contend__contains="ray")
print(grades)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
查詢的快捷方式: pk pk表示主鍵,默認主鍵是id
聚合函數(shù)
注意: 使用aggregate()函數(shù)返回聚合函數(shù)的值
函數(shù): Avg、Count、Max、Min、Sum
# 求所有人的年齡的和
from django.db.models import Sum
def students(request):
age = Student.objects.aggregate(Sum("age"))
print("***********", age)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
F對象
作用: 可以使模型中的A字段與B字段進行比較,如果A字段出現(xiàn)在等號的左側,那么B字段使用F對象寫在等號右側
# 找男生個數(shù)多于女生個數(shù)的班級
from django.db.models import F
def students(request):
grades = Grade.objects.filter(boyNum__gt=F("girlNum"))
print(grades)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
F對象可以進行數(shù)學運算
from django.db.models import F
def students(request):
grades = Grade.objects.filter(boyNum__gt=F("girlNum")*2)
print(grades)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
F對象還可以進行關聯(lián)查詢 模型類小寫__屬性名
# 沒有被刪除的學生的班級
from django.db.models import F
def students(request):
grades = Grade.objects.filter(isDelete=F("student__isDelete"))
print(grades)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
對于data/time字段,可以進行timedelta()進行運算
Q對象
邏輯與
# 年齡大于等于20且小于等于50的學生
def students(request):
stus = Student.objects.filter(age__gte=20,age__lte=50)
return render(request, 'students.html', {"stus":stus})
def students(request):
stus = Student.objects.filter(age__gte=20).filter(age__lte=50)
return render(request, 'students.html', {"stus":stus})
from django.db.models import Q
def students(request):
stus = Student.objects.filter(Q(age__gte=20) & Q(age__lte=50))
return render(request, 'students.html', {"stus":stus})
邏輯或
# 獲取年齡小于20或者年齡大于50的學生
from django.db.models import Q
def students(request):
stus = Student.objects.filter(Q(age__lt=20) | Q(age__gt=50))
return render(request, 'students.html', {"stus":stus})
邏輯非
# 獲取年齡不大于等于20的學生
def students(request):
stus = Student.objects.filter(age__lt=20)
return render(request, 'students.html', {"stus":stus})
from django.db.models import Q
def students(request):
stus = Student.objects.filter(~Q(age__gte=20))
return render(request, 'students.html', {"stus":stus})
注意: 過濾器函數(shù)中可以混合使用Q對象和關鍵字參數(shù),所有參數(shù)條件都將and在一起,Q對象必須位于關鍵字參數(shù)的前面
def students(request):
stus = Student.objects.all()[5:10]#[0:5)
return render(request, 'students.html', {"stus":stus})
模型關系
1-1
使用場景: 表的字段太多,需要拆分
# 人
class Person(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
# 關系存放在哪張表都可以
# 綁定身份證與人的一對一關系,默認情況下當刪身份證時綁定的人也可以刪除,通過on_delete屬性設置
idCard = models.OneToOneField(IDCard)
# 身份證
class IDCard(models.Model):
sex = models.BooleanField()
num = models.CharField(max_length=20)
主表從表: 聲明關系的表為從表
級聯(lián)數(shù)據(jù)獲?。?/p>
從獲取主:
- 關系是直接聲明的,是一個顯性的屬性
- 獲取pk為1的人的身份證號
- per = Person.objects.get(pk=1) print(per.idCard.num)
主獲取從:
- 關系字段是隱性屬性,對象.關系模型類名的小寫
- 獲取身份證號是1的人的姓名
- card = IDCard.objects.get(pk=1) print(card.person.name)

1-n
一對多,也就是外鍵。
主表從表: 聲明關系的表為從表(ForeignKey)。
級聯(lián)數(shù)據(jù)獲取:
- 從獲取主: 關系是直接聲明的,是一個顯性的屬性
- 主獲取從: 關系字段是隱性屬性,對象.模型類小寫_set
#找到1班的所有學生
grade = Grade.objects.get(pk=1)
print(grade.student_set.all())
m-n
原理: 底層是通過兩個外鍵實現(xiàn),兩個外鍵存在于另一張關系表中
#多對多
class Buyer(models.Model):
name = models.CharField(max_length=20)
level = models.IntegerField()
class Product(models.Model):
name = models.CharField(max_length=20)
price = models.IntegerField()
#關系形成
buyers = models.ManyToManyField(Buyer)
形成關系
def ptob(reqeust, p, b):
product = Product.objects.get(pk=p)
buyer = Buyer.objects.get(pk=b)
#產(chǎn)生關聯(lián)
product.buyers.add(buyer)
return HttpResponse("購買成功")
數(shù)據(jù)級聯(lián)獲取
從獲取主
- 對象.顯性屬性,得到的是一個數(shù)據(jù)集合,可以進行過濾
- 已知一件商品,獲取該商品所有的購買者
- product = Product.objects.get(pk=1) print(product.buyers.all())
主獲取從:
- 隱性屬性 對象.關聯(lián)類名小寫_set 得到的是一個數(shù)據(jù)集合,可以進行過濾
- 已知一個購買者,獲取他所買的所有商品
- buyer = Buyer.objects.get(pk=1) print(buyer.product_set.all())
模型繼承
使用最原始的python類的繼承方式
class Animal(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
class Cat(Animal):
weight = models.IntegerField()
class Dog(Animal):
height = models.IntegerField()
注意: 默認繼承方式不是很合理
- 父類也會對應一張表
- 默認在父類中定義的字段會存在父類表中,子類的數(shù)據(jù)通過外鍵關聯(lián)父表中數(shù)據(jù),子類只有特殊的數(shù)據(jù)在子表中
- 效率比較低
Django中的數(shù)據(jù)庫模塊提供了一個非常不錯的功能,就是支持models的面向對象,可以在Meta類中指定是否抽象,然后繼承
class Animal(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
class Meta():
# 讓該類抽象,抽象的父類不會再生產(chǎn)數(shù)據(jù)表
# 子類會繼承父類中的通用數(shù)據(jù),復制到子表中
abstract = True
class Cat(Animal):
weight = models.IntegerField()
class Dog(Animal):
height = models.IntegerField()