ORM
??ORM框架的目的是不再使用SQL語(yǔ)句,讓用戶使用對(duì)象類和對(duì)象的方式和這個(gè)框架內(nèi)部的方法來(lái)進(jìn)行數(shù)據(jù)庫(kù)操作,對(duì)于ORM框架來(lái)說(shuō),把類和對(duì)象轉(zhuǎn)換成SQL語(yǔ)句.
優(yōu)點(diǎn):
?1.ORM提供了對(duì)數(shù)據(jù)庫(kù)的映射,不用直接編寫(xiě)SQL代碼,只需要操作對(duì)象就能對(duì)數(shù)據(jù)庫(kù)操作數(shù)據(jù)
?2.讓軟件開(kāi)發(fā)人員專注于業(yè)務(wù)邏輯的處理,提高了開(kāi)發(fā)的效率
缺點(diǎn):
?1.ORM的缺點(diǎn)是會(huì)在一定程度上犧牲程序的執(zhí)行效率
?2.ORM的操作是有限的,也就是ORM定義好的操作是可以完成的
對(duì)應(yīng)關(guān)系:
?類 ?。尽?shù)據(jù)表
?對(duì)象?。尽?shù)據(jù)行
?屬性 --> 字段
ORM表模型
一對(duì)一(one-to-one)
實(shí)質(zhì)就是在主外鍵的關(guān)系基礎(chǔ)上,給外鍵加了一個(gè)unique=Ture的屬性,方法OneToOnefiled()
一對(duì)多(one-to-many)
什么時(shí)候需要外鍵
??一張表里的數(shù)據(jù)會(huì)在其它多個(gè)表中被使用,這個(gè)數(shù)據(jù)就會(huì)被稱為外鍵
在Django中使用外鍵
publisher = models.Foreignkey(to='類名')
ORM在數(shù)據(jù)庫(kù)中創(chuàng)建該字段的時(shí)候會(huì)默認(rèn)在后面加_id
在ORM中使用外鍵
book_obj.publisher --> 表示的是和書(shū)關(guān)聯(lián)的出版社對(duì)象(ORM幫我們封裝的)
book_obj.publisher_id --> 表示數(shù)據(jù)庫(kù)中真正保存的字段(int)
多對(duì)多(many-to-many)
語(yǔ)法:book = models.ManyToManyField(to='book')
自動(dòng)創(chuàng)建第三張表:實(shí)質(zhì)就是創(chuàng)建了兩個(gè)foreign_key
什么是QuerySet
從數(shù)據(jù)庫(kù)中查詢出來(lái)的結(jié)果一般是一個(gè)集合,這個(gè)集合叫做QuerySet。
注意:
(1)QuerySet是可以迭代的
(2)支持切片
(3)可以用len()和count()函數(shù)測(cè)量數(shù)量。
(4)可以通過(guò)list()函數(shù)強(qiáng)行變成列表。
ORM的增刪查改
查
類名.objects.all() --> 查找數(shù)據(jù)庫(kù)中該表的所有數(shù)據(jù)
類名.objects.filter(條件) --> 根據(jù)給定的條件取數(shù)據(jù)庫(kù)中查找,返回的是列表
類名.objects.get(條件) --> 根據(jù)條件找到一個(gè)對(duì)象(找到多個(gè)或者找不到都報(bào)錯(cuò)),返回的是對(duì)象
多對(duì)多的查詢:
author_obj.book.all() ---> 返回一個(gè)書(shū)籍的列表
增
類名.objects.create()
多對(duì)多的增加:
對(duì)象.book.add(id1, id2) --> 多對(duì)多添加關(guān)聯(lián)的數(shù)據(jù)
刪
類名.objects.filter(條件).delete()
類名.objects.get(條件).delete()
多對(duì)多的刪除:
對(duì)象.book.clear()
補(bǔ)充Django2.0以上的版本,外鍵需要手動(dòng)設(shè)置級(jí)聯(lián)操作 on_delete=models.CASCADE
改
obj = 類名.objects.get(條件)
obj.屬性 = ‘新值’
obj.save()
類名.objects.filter(條件).update(字段=‘新值’)
多對(duì)多的修改:
author_obj.book.set([id1, id2]) --> 多對(duì)多的設(shè)置關(guān)聯(lián)的數(shù)據(jù)
外鍵的增刪查改
- 查
Book.objects.all() --> 返回的是一個(gè)列表(QuerySet)
Book.objects.filter() --> 返回的是一個(gè)列表(QuerySet)
Book.objects.get() --> 返回的是一個(gè)具體書(shū)籍對(duì)象
- 刪
Book.objects.filter().delete()
Book.objects.get().delete()
- 增
Book.objects.create(title='', publisher='出版社對(duì)象')
Book.objects.create(title='', publisher_id='出版社id值')
- 改
(1) 基于對(duì)象的修改
book_obj = Book.objects.get(id='id值')
book_obj.title = '書(shū)名'
book_obj.publisher_id = '出版社id值'
book_obj.save()
(2) 基于QuerySet的修改
Book.objects.filter(id='id值').update(title='值',publisher_id='值')
ORM常用字段和參數(shù)
常用字段
AutoField
int自增列,必須填入?yún)?shù)primary_key=Ture.當(dāng)model中如果沒(méi)有自增列的時(shí)候會(huì)自動(dòng)創(chuàng)建
IntegerField
一個(gè)整數(shù)類型,范圍在-2147483648 to 2147483647,只有10位不能表示手機(jī)號(hào)。
CharField
字符類型,必須提供max_length參數(shù), max_length表示字符長(zhǎng)度。
DataField
日期字段,日期格式 YYYY-MM-DD,相當(dāng)于Python中的datetime.date()實(shí)例。
Data TimeField
日期時(shí)間字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當(dāng)于Python中的datetime.datetime()實(shí)例
DecimalField
小數(shù)字段
DecimalField(max_digits=5, decimal_places=2),max_digits定義小數(shù)總長(zhǎng)度,decimal_places`定義小數(shù)位數(shù)
其它字段
BigAutoField(AutoField)
- bigint自增列,必須填入?yún)?shù) primary_key=True
注:當(dāng)model中如果沒(méi)有自增列,則自動(dòng)會(huì)創(chuàng)建一個(gè)列名為id的列
from django.db import models
class UserInfo(models.Model):
# 自動(dòng)創(chuàng)建一個(gè)列名為id的且為自增的整數(shù)列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定義自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整數(shù) -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整數(shù) 0 ~ 32767
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整數(shù) 0 ~ 2147483647
BigIntegerField(IntegerField):
- 長(zhǎng)整型(有符號(hào)的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field)
- 布爾值類型
NullBooleanField(Field):
- 可以為空的布爾值
TextField(Field)
- 文本類型
EmailField(CharField):
- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證機(jī)制
IPAddressField(Field)
- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 IPV4 機(jī)制
GenericIPAddressField(Field)
- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 Ipv4和Ipv6
- 參數(shù):
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定為True,則輸入::ffff:192.0.2.1時(shí)候,可解析為192.0.2.1,開(kāi)啟此功能,需要protocol="both"
URLField(CharField)
- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 URL
SlugField(CharField)
- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證支持 字母、數(shù)字、下劃線、連接符(減號(hào))
CommaSeparatedIntegerField(CharField)
- 字符串類型,格式必須為逗號(hào)分割的數(shù)字
UUIDField(Field)
- 字符串類型,Django Admin以及ModelForm中提供對(duì)UUID格式的驗(yàn)證
FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
- 參數(shù):
path, 文件夾路徑
match=None, 正則匹配
recursive=False, 遞歸下面的文件夾
allow_files=True, 允許文件
allow_folders=False, 允許文件夾
FileField(Field)
- 字符串,路徑保存在數(shù)據(jù)庫(kù),文件上傳到指定目錄
- 參數(shù):
upload_to = "" 上傳文件的保存路徑
storage = None 存儲(chǔ)組件,默認(rèn)django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路徑保存在數(shù)據(jù)庫(kù),文件上傳到指定目錄
- 參數(shù):
upload_to = "" 上傳文件的保存路徑
storage = None 存儲(chǔ)組件,默認(rèn)django.core.files.storage.FileSystemStorage
width_field=None, 上傳圖片的高度保存的數(shù)據(jù)庫(kù)字段名(字符串)
height_field=None 上傳圖片的寬度保存的數(shù)據(jù)庫(kù)字段名(字符串)
TimeField(DateTimeCheckMixin, Field)
- 時(shí)間格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 長(zhǎng)整數(shù),時(shí)間間隔,數(shù)據(jù)庫(kù)中按照bigint存儲(chǔ),ORM中獲取的值為datetime.timedelta類型
FloatField(Field)
- 浮點(diǎn)型
DecimalField(Field)
- 10進(jìn)制小數(shù)
- 參數(shù):
max_digits,小數(shù)總長(zhǎng)度
decimal_places,小數(shù)位長(zhǎng)度
BinaryField(Field)
- 二進(jìn)制類型
自定義字段
class UnsignedIntegerField(models.IntegerField):
def db_type(self, connection):
return 'integer UNSIGNED'
自定義char類型字段:
class FixedCharField(models.Field):
"""
自定義的char類型的字段類
"""
def __init__(self, max_length, *args, **kwargs):
super().__init__(max_length=max_length, *args, **kwargs)
self.length = max_length
def db_type(self, connection):
"""
限定生成數(shù)據(jù)庫(kù)表的字段類型為char,長(zhǎng)度為length指定的值
"""
return 'char(%s)' % self.length
class Class(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=25)
# 使用上面自定義的char類型的字段
cname = FixedCharField(max_length=25)
常用的字段參數(shù)
null 數(shù)據(jù)庫(kù)中字段是否可以為空
db_column 數(shù)據(jù)庫(kù)中字段的列名
default 數(shù)據(jù)庫(kù)中字段的默認(rèn)值
primary_key 數(shù)據(jù)庫(kù)中字段是否為主鍵
db_index 數(shù)據(jù)庫(kù)中字段是否可以建立索引
unique 數(shù)據(jù)庫(kù)中字段是否可以建立唯一索引
unique_for_date 數(shù)據(jù)庫(kù)中字段【日期】部分是否可以建立唯一索引
unique_for_month 數(shù)據(jù)庫(kù)中字段【月】部分是否可以建立唯一索引
unique_for_year 數(shù)據(jù)庫(kù)中字段【年】部分是否可以建立唯一索引
DatetimeField和Datefield獨(dú)有:
auto_now_add --> 當(dāng)前數(shù)據(jù)的創(chuàng)建時(shí)間
auto_now --> 當(dāng)前數(shù)據(jù)的最后修改時(shí)間
帶choice參數(shù)的字段
get_字段名_display()
建表的元信息
class Meta:
db_table = '表名'
unique_together = (('ip', 'port'),)
index_together = (("pub_date", "deadline"),)
必知必會(huì)13條
- 返回QuerySet列表類型的
1. filter():篩選條件匹配的對(duì)象
2. all():查詢所有的結(jié)果
3. exclude():篩選出與條件不匹配的對(duì)象
4. order_by():對(duì)查詢的結(jié)果排序
5. reverse():對(duì)查詢的結(jié)果反向排序
6. distinct():從返回結(jié)果中剔除重復(fù)紀(jì)錄(如果你查詢跨越多個(gè)表,可能在計(jì)算QuerySet時(shí)得到重復(fù)的結(jié)果。此時(shí)可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
7. values(): 返回一個(gè)ValueQuerySet——一個(gè)特殊的QuerySet,運(yùn)行后得到的并不是一系列model的實(shí)例化對(duì)象,而是一個(gè)可迭代的字典序列
8. values_list() :它與values()非常相似,它返回的是一個(gè)元組序列,values返回的是一個(gè)字典序列
2. 返回具體對(duì)象
1. get():返回與所給篩選條件相匹配的對(duì)象,返回結(jié)果有且只有一個(gè),如果符合篩選條件的對(duì)象超過(guò)一個(gè)或者沒(méi)有都會(huì)拋出錯(cuò)誤。
2. first():返回第一條記錄
3. last():返回最后一條記錄
3. 返回布爾值
1. exists():如果QuerySet包含數(shù)據(jù),就返回True,否則返回False
4. 返回?cái)?shù)字的
1. count():返回?cái)?shù)據(jù)庫(kù)中匹配查詢(QuerySet)的對(duì)象數(shù)量。
神奇的下劃線(單表查詢)
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大于1 且 小于10的值
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等于11、22、33的數(shù)據(jù)
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
models.Tb1.objects.filter(name__contains="ven") # 獲取name字段包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫(xiě)不敏感
models.Tb1.objects.filter(id__range=[1, 3]) # id范圍是1到3的,等價(jià)于SQL的bettwen and
類似的還有:startswith,istartswith, endswith, iendswith
date字段還可以:
models.Class.objects.filter(first_day__year=2017)
ORM關(guān)聯(lián)查詢
基于對(duì)象的查詢
正向查詢
對(duì)象.關(guān)聯(lián)字段
反向查詢
1.默認(rèn)不設(shè)置related_name屬性
(1)查找的對(duì)象是多個(gè)的時(shí)候(一對(duì)多或者多對(duì)多)
publisher_obj.book_set.all()
(2)查找一個(gè)對(duì)象時(shí)(一對(duì)一)
author_info_obj.autjor.name
2.設(shè)置related_name=‘books’屬性
publisher_obj.books.all()
基于QuerySet的查詢
正向查詢
Book.objects.filter(id=1).values_list(‘publisher__name’)
反向查詢
1.默認(rèn)不設(shè)置related_name屬性,默認(rèn)就用類名的小寫(xiě)
Publisher.objects.filter(id=1).values_list(‘book__price’) 2.設(shè)置related_name屬性Publisher.objects.filter(id=1).values_list(‘books__price’)
聚合查詢和分組查詢
聚合
Django在django.db.models中提供了許多聚合函數(shù),aggregate()是Queryset的一個(gè)終止子句,意思是它返回一個(gè)包含鍵值對(duì)的字典不能使用values()和value_list()
聚合函數(shù):
from django.db.models import Avg,Sum,Max,Min,Count:
假如要求一個(gè)表中某個(gè)數(shù)值列的平均數(shù)
from django.db.models import Avg,Sum,Max,Min,Count:
表名.objects.all().aggregate(Avg('列名'))
也可以指定一個(gè)名字
表名.objects.all().aggregate(昵稱=Avg('列名'))
也可以使用多個(gè)聚合函數(shù)
表名.objects.all().aggregate(Avg('列名'),Max('列名'))
分組
假設(shè)現(xiàn)在有一張公司職員表:

我們使用原生SQL語(yǔ)句,按照部分分組求平均工資:
select dept,AVG(salary) from employee group by dept;
ORM查詢:
from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
連表查詢的分組:

SQL查詢:
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
ORM查詢:
from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
F查詢和 Q查詢
F查詢
當(dāng)我們需要進(jìn)行兩個(gè)字段的值作比較的時(shí)候我們使用F()來(lái)做比較.F() 的實(shí)例可以在查詢中引用字段,來(lái)比較同一個(gè) model 實(shí)例中兩個(gè)不同字段的值。
查詢?cè)u(píng)論數(shù)大于收藏?cái)?shù)的書(shū)籍
from django.db.models import F
models.Book.objects.filter(commnet_num__gt=F('keep_num'))
Django 支持 F() 對(duì)象之間以及 F() 對(duì)象和常數(shù)之間的加減乘除和取模的操作。
models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)
修改操作也可以使用F函數(shù),比如將每一本書(shū)的價(jià)格提高30元
models.Book.objects.all().update(price=F("price")+30)
如果要修改char字段咋辦?
如:把所有書(shū)名后面加上(第一版)
>>> from django.db.models.functions import Concat
>>> from django.db.models import Value
>>> models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))
Q查詢
filter() 等方法中的關(guān)鍵字參數(shù)查詢都是一起進(jìn)行“AND” 的。 如果你需要執(zhí)行更復(fù)雜的查詢(例如OR語(yǔ)句),你可以使用Q對(duì)象。
你可以組合& 和| 操作符以及使用括號(hào)進(jìn)行分組來(lái)編寫(xiě)任意復(fù)雜的Q 對(duì)象。同時(shí),Q 對(duì)象可以使用~ 操作符取反,這允許組合正常的查詢和取反(NOT) 查詢。
示例:查詢作者名字是小仙女并且不是2018年出版的書(shū)的書(shū)名
models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")
查詢函數(shù)可以混合使用Q 對(duì)象和關(guān)鍵字參數(shù)。所有提供給查詢函數(shù)的參數(shù)(關(guān)鍵字參數(shù)或Q 對(duì)象)都將"AND”在一起。但是,如果出現(xiàn)Q 對(duì)象,它必須位于所有關(guān)鍵字參數(shù)的前面。
例如:查詢出版年份是2017或2018,書(shū)名中帶物語(yǔ)的所有書(shū)。
models.Book.objects.filter(Q(publish_date__year=2018) | Q(publish_date__year=2017), title__icontains="物語(yǔ)")
在Django終端打印SQL語(yǔ)句
在Django項(xiàng)目的settings.py文件中,在最后復(fù)制粘貼如下代碼:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}