東莞專業(yè)網(wǎng)站設(shè)計(jì)咨詢線上運(yùn)營(yíng)推廣
?ORM的介紹
# ORM是什么?
????????我們?cè)谑褂肈jango框架開發(fā)web應(yīng)用的過程中,不可避免地會(huì)涉及到數(shù)據(jù)的管理操作(增、刪、改、查),而一旦談到數(shù)據(jù)的管理操作,就需要用到數(shù)據(jù)庫(kù)管理軟件,例如mysql、oracle、Microsoft SQL Server等。
# ORM的概念:
????????ORM全稱Object Relational Mapping,即對(duì)象關(guān)系映射,是在pymysq之上又進(jìn)行了一層封裝,對(duì)于數(shù)據(jù)的操作,我們無(wú)需再去編寫原生sql,取代代之的是基于面向?qū)ο蟮乃枷肴ゾ帉戭悺?duì)象、調(diào)用相應(yīng)的方法等,ORM會(huì)將其轉(zhuǎn)換/映射成原生SQL然后交給pymysql執(zhí)行
![]()
ORM的使用之?dāng)?shù)據(jù)庫(kù)遷移
1、創(chuàng)建模型:數(shù)據(jù)來(lái)源于數(shù)據(jù)庫(kù)的表,而ORM的模型類對(duì)應(yīng)數(shù)據(jù)庫(kù)表
# 創(chuàng)建django項(xiàng)目,新建名為app01的app,在app01的models.py中創(chuàng)建模型 class Employee(models.Model): # 必須是models.Model的子類id=models.AutoField(primary_key=True)name=models.CharField(max_length=16)gender=models.BooleanField(default=1)birth=models.DateField()department=models.CharField(max_length=30)salary=models.DecimalField(max_digits=10,decimal_places=1)
2、 配置settings.py
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles', 'app01.apps.App01Config', # django2.x+版本 # 'app01', # django1.x版本]DATABASES = { # 刪除\注釋掉原來(lái)的DATABASES配置項(xiàng),新增下述配置'default': {'ENGINE': 'django.db.backends.mysql', # 使用mysql數(shù)據(jù)庫(kù)'NAME': 'db1', # 要連接的數(shù)據(jù)庫(kù)'USER': 'root', # 鏈接數(shù)據(jù)庫(kù)的用于名'PASSWORD': '', # 鏈接數(shù)據(jù)庫(kù)的用于名 'HOST': '127.0.0.1', # mysql服務(wù)監(jiān)聽的ip 'PORT': 3306, # mysql服務(wù)監(jiān)聽的端口 'ATOMIC_REQUEST': True, #設(shè)置為True代表同一個(gè)http請(qǐng)求所對(duì)應(yīng)的所有sql都放在一個(gè)事務(wù)中
3.配置日志:如果想打印orm轉(zhuǎn)換過程中的sql,需要在settings中進(jìn)行配置日志
LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'console':{'level':'DEBUG','class':'logging.StreamHandler',},},'loggers': {'django.db.backends': {'handlers': ['console'],'propagate': True,'level':'DEBUG',},} }
4、數(shù)據(jù)庫(kù)遷移命令
python manage.py makemigrations python manage.py migrate
?模型層models:表查詢
?模型層的表查詢:跟數(shù)據(jù)庫(kù)打交道的
1、單表查詢:
? ? ? ? insert update delete all filter
2、常見的查詢方法:
單表操作: ? ? 1、all() ? ? ?查詢所有數(shù)據(jù),索引取值 ? ?2、filter() ? 過濾條件查詢 ? ? 3、get() ? ? ?查詢數(shù)據(jù),查詢數(shù)據(jù)為空的情況直接報(bào)錯(cuò) ? ? 4、last() ? ? 取所有數(shù)據(jù)的最后一條 ? ? 5、values( id,username,password ) ? 取值,列表套字典[{'id':1,'username':...},{...}] ? ? 6、vallues_list() ? ? ? ? ? ? ? ? ? 取值,列表套元組,都支持for循環(huán) ? ? 7、pring(res.quert) ? 查看內(nèi)部的SQL語(yǔ)句,只有防御的結(jié)果是queryset對(duì)象的時(shí)候才能查看 ? ? 8、distinct() ? ? ? ? 去重 ? ? 9、order_by( 'id' ) ? 默認(rèn)情況升序排序;('-id')倒序 ? ? 10、reverse() ? ? ? ? 翻轉(zhuǎn) ? ? 11、count() ? ? ? ? ? 統(tǒng)計(jì)當(dāng)前表中數(shù)據(jù)的個(gè)數(shù) ? ? 12、exclude(pk=1) ? ? 排除在外 ? ? 13、exists() ? ? ? ? ?看數(shù)據(jù)到底有沒有
3、基于雙下劃線的查詢:
res = models.UserInfo.object.filter(age_gt=38).all() age__gt=1---大于 age__lt=1---小于 age__gte=1---大于等于 age__lte=1---小于等于 ageage__in=[18,40] 年齡在十八或40的,或 age__range=[18,40] 年齡在十八到40的,之間
?# 包含s的數(shù)據(jù),模糊查詢:? ?
包含s的數(shù)據(jù),模糊查詢:# select * from userinfor where name like '%s%',res = models.UserInfo.object.filter(username__contains='s').all()print(res)print(res.query) username__icontains--忽略大小寫 username__startswith=='o'--以o開頭的 username__endswith=='o'--以o結(jié)尾的
# 日期查詢:
register_time = models.DateTimeField(auto_now=True,auto_now_add=True,null=True) auto_now: 修改的時(shí)間 auto_now_add: 剛加進(jìn)去時(shí)間 查詢時(shí)間:查2020年1月份的 filter(register_time__year='2020',register_time__month='01).all()
多表查詢(跨表查詢)
子查詢:分步查詢
鏈表查詢:把多個(gè)有關(guān)系的表拼接成一個(gè)大表(虛擬表)
?? ?????????inner join?
????????? ? left join
????????? ? right join
基于雙下劃線的查詢
年齡大于35歲的數(shù)據(jù):
????????res = models.User.objects.filter(age__gt=35)
年齡小于35歲的數(shù)據(jù):
????????res = models.User.objects.filter(age__lt=35)
大于等于 小于等于:
????????res = models.User.objects.filter(age__gte=32)
????????res = models.User.objects.filter(age__lte=32)
年齡是18 或者 32 或者40:
????????res = models.User.objects.filter(age__in=[18,32,40])
年齡在18到40歲之間的 ?首尾都要:
????????res = models.User.objects.filter(age__range=[18,40])
查詢出名字里面含有s的數(shù)據(jù) ?模糊查詢:
????????res = models.User.objects.filter(name__contains='s')
是否區(qū)分大小寫 ?查詢出名字里面含有p的數(shù)據(jù) ?區(qū)分大小寫:
????????res = models.User.objects.filter(name__contains='p')
忽略大小寫:
????????res = models.User.objects.filter(name__icontains='p')
以 'j' 開頭或以 'j' 結(jié)尾:
? ? ? ?res = models.User.objects.filter(name__startswith='j')
? ? ???res1 = models.User.objects.filter(name__endswith='j')查詢出注冊(cè)時(shí)間是 2020 1月:
????????res = models.User.objects.filter(register_time__month='1')
????????res = models.User.objects.filter(register_time__year='2020')
多表查詢前期表準(zhǔn)備
class Book(models.Model):title = models.CharField(max_length=32)price = models.DecimalField(max_digits=8,decimal_places=2)publish_date = models.DateField(auto_now_add=True)# 一對(duì)多publish = models.ForeignKey(to='Publish')# 多對(duì)多authors = models.ManyToManyField(to='Author')class Publish(models.Model):name = models.CharField(max_length=32)addr = models.CharField(max_length=64)# varchar(254) 該字段類型不是給models看的 而是給后面我們會(huì)學(xué)到的校驗(yàn)性組件看的def __str__(self):return self.nameclass Author(models.Model):name = models.CharField(max_length=32)age = models.IntegerField()# 一對(duì)一author_detail = models.OneToOneField(to='AuthorDetail')class AuthorDetail(models.Model):phone = models.BigIntegerField() # 電話號(hào)碼用BigIntegerField或者直接用CharFieldaddr = models.CharField(max_length=64)
一對(duì)多外鍵增刪改查
# 增:
方式一:直接寫實(shí)際字段 id models.Book.objects.create(title='論語(yǔ)',price=899.23,publish_id=1) models.Book.objects.create(title='聊齋',price=444.23,publish_id=2) models.Book.objects.create(title='老子',price=333.66,publish_id=1) 方式二:虛擬字段 對(duì)象 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.create(title='紅樓夢(mèng)',price=666.23,publish=publish_obj)
# 刪:??models.Publish.objects.filter(pk=1).delete() ?# 級(jí)聯(lián)刪除
# 修改
models.Book.objects.filter(pk=1).update(publish_id=2) publish_obj = models.Publish.objects.filter(pk=1).first() models.Book.objects.filter(pk=1).update(publish=publish_obj)
多對(duì)多外鍵增刪改查
# 增,給書籍添加作者:
book_obj = models.Book.objects.filter(pk=1).first() print(book_obj.authors) # 就類似于你已經(jīng)到了第三張關(guān)系表了 book_obj.authors.add(1) # 書籍id為1的書籍綁定一個(gè)主鍵為1 的作者 book_obj.authors.add(2,3)author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() author_obj2 = models.Author.objects.filter(pk=3).first() book_obj.authors.add(author_obj) """add給第三張關(guān)系表添加數(shù)據(jù),括號(hào)內(nèi)既可以傳數(shù)字也可以傳對(duì)象 并且都支持多個(gè)"""
# 刪:
book_obj.authors.remove(2) book_obj.authors.remove(1,3)author_obj = models.Author.objects.filter(pk=2).first() author_obj1 = models.Author.objects.filter(pk=3).first() book_obj.authors.remove(author_obj,author_obj1) """remove,括號(hào)內(nèi)既可以傳數(shù)字也可以傳對(duì)象 并且都支持多個(gè)"""
# 修改:
book_obj.authors.set([1,2]) # 括號(hào)內(nèi)必須給一個(gè)可迭代對(duì)象 book_obj.authors.set([3]) # 括號(hào)內(nèi)必須給一個(gè)可迭代對(duì)象author_obj = models.Author.objects.filter(pk=2).first() author_obj1 = models.Author.objects.filter(pk=3).first() book_obj.authors.set([author_obj,author_obj1]) # 括號(hào)內(nèi)必須給一個(gè)可迭代對(duì)象
# 清空,在第三張關(guān)系表中清空某個(gè)書籍與作者的綁定關(guān)系
????????book_obj.authors.clear()?
? clear括號(hào)內(nèi)不要加任何參數(shù)
正反向的概念
正向:外鍵字段在我手上那么,我查你就是正向,按 外鍵字段
反向:外鍵字段如果不在手上,我查你就是反向,按 表名小寫
????????? book >>>外鍵字段在書那兒(正向)>>> publish
????????? publish?? ?>>>外鍵字段在書那兒(反向)>>>book
?_set
多表查詢之子查詢
子查詢---基于對(duì)象的跨表查詢
1.查詢書籍主鍵為1的出版社:
book_obj = models.Book.objects.filter(pk=1).first() # 書查出版社 正向 res = book_obj.publish print(res) print(res.name) print(res.addr)
2.查詢書籍主鍵為2的作者:
book_obj = models.Book.objects.filter(pk=2).first() # 書查作者 正向 res = book_obj.authors ? # app01.Author.None res = book_obj.authors.all() ? # 查的多的話要用all() print(res)
3.查詢作者jason的電話號(hào)碼:
author_obj = models.Author.objects.filter(name='jason').first() res = author_obj.author_detail print(res) print(res.phone) print(res.addr)
4.查詢出版社是東方出版社出版的書:
publish_obj = models.Publish.objects.filter(name='東方出版社').first() # 出版社查書 ?反向 res = publish_obj.book_set ? # app01.Book.None res = publish_obj.book_set.all() print(res)
5.查詢作者是jason寫過的書:
author_obj = models.Author.objects.filter(name='jason').first() # 作者查書 反向 res = author_obj.book_set ?# app01.Book.None res = author_obj.book_set.all() print(res)
6.查詢手機(jī)號(hào)是110的作者姓名:
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first() res = author_detail_obj.author print(res.name)
# 如果是一個(gè)則直接拿到數(shù)據(jù)對(duì)象
? ? ? ? ? ? book_obj.publish
? ? ? ? ? ? book_obj.authors.all()
? ? ? ? ? ? author_obj.author_detail# 在書寫orm語(yǔ)句的時(shí)候跟寫sql語(yǔ)句一樣的,不要企圖一次性將orm語(yǔ)句寫完 如果比較復(fù)雜 就寫一點(diǎn)看一點(diǎn)
# 基于對(duì)象 : 反向查詢的時(shí)候
? ? ? ? 當(dāng)你的查詢結(jié)果可以有多個(gè)的時(shí)候 就必須加_set.all()
? ? ? ? 當(dāng)你的結(jié)果只有一個(gè)的時(shí)候 不需要加_set.all()
多表查詢之聯(lián)表查詢
聯(lián)表查詢---基于雙下劃線的跨表查詢
1.查詢jason的手機(jī)號(hào)和作者姓名:
res = models.Author.objects.filter(name='jason').values('author_detail__phone','name') print(res) # 反向 res = models.AuthorDetail.objects.filter(author__name='jason') ?# 拿作者姓名是jason的作者詳情 res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__name') print(res)
2.查詢書籍主鍵為1的出版社名稱和書的名稱:
res = models.Book.objects.filter(pk=1).values('title','publish__name') print(res) # 反向 res = models.Publish.objects.filter(book__id=1).values('name','book__title') print(res)
3.查詢書籍主鍵為1的作者姓名:
res = models.Book.objects.filter(pk=1).values('authors__name') print(res) # 反向 res = models.Author.objects.filter(book__id=1).values('name') print(res)
4.查詢書籍主鍵是1的作者的手機(jī)號(hào):
book author authordetail res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone') print(res)
# 你只要掌握了正反向的概念以及雙下劃線,那么你就可以無(wú)限制的跨表
多表查詢之分組查詢
select age from t group by age; """MySQL分組查詢都有哪些特點(diǎn)分組之后默認(rèn)只能獲取到分組的依據(jù) 組內(nèi)其他字段都無(wú)法直接獲取了嚴(yán)格模式ONLY_FULL_GROUP_BYset global sql_mode='ONLY_FULL_GROUP_BY' """
#?你們的機(jī)器上如果出現(xiàn)分組查詢報(bào)錯(cuò)的情況,你需要修改數(shù)據(jù)庫(kù)嚴(yán)格模式
# 分組查詢 ?annotate
from django.db.models import Max, Min, Sum, Count, Avg
1.統(tǒng)計(jì)每一本書的作者個(gè)數(shù):
res = models.Book.objects.annotate() ?# models后面點(diǎn)什么 就是按什么分組 res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') res1 = models.Book.objects.annotate(author_num=Count('authors__id')).values('title','author_num') print(res,res1) """author_num是我們自己定義的字段 用來(lái)存儲(chǔ)統(tǒng)計(jì)出來(lái)的每本書對(duì)應(yīng)的作者個(gè)數(shù)"""
2.統(tǒng)計(jì)每個(gè)出版社賣的最便宜的書的價(jià)格:
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price') print(res)
3.統(tǒng)計(jì)不止一個(gè)作者的圖書:
? ? ? ? # 先按照?qǐng)D書分組 求每一本書對(duì)應(yīng)的作者個(gè)數(shù)
? ? ? ? # 過濾出不止一個(gè)作者的圖書res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num') print(res)
4.查詢每個(gè)作者出的書的總價(jià)格:
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price') print(res)
# 代碼沒有補(bǔ)全 不要怕,正常寫,補(bǔ)全給你是pycharm給你的,到后面在服務(wù)器上直接書寫代碼,什么補(bǔ)全都沒有,顏色提示也沒有
#?只要你的orm語(yǔ)句得出的結(jié)果還是一個(gè)queryset對(duì)象,那么它就可以繼續(xù)無(wú)限制的點(diǎn)queryset對(duì)象封裝的方法
F查詢
F查詢:能夠幫助你直接獲取到表中某個(gè)字段對(duì)應(yīng)的數(shù)據(jù)
1.查詢賣出數(shù)大于庫(kù)存數(shù)的書籍:
from django.db.models import F res = models.Book.objects.filter(maichu__gt=F('kucun')) print(res)
2.將所有書籍的價(jià)格提升500塊:
????????models.Book.objects.update(price=F('price') + 500)3.將所有書的名稱后面加上爆款兩個(gè)字:
from django.db.models.functions import Concat #拼接字符串 from django.db.models import Value models.Book.objects.update(title=Concat(F('title'), Value('爆款'))) # models.Book.objects.update(title=F('title') + '爆款') ?# 所有的名稱會(huì)全部變成空白 """在操作字符類型的數(shù)據(jù)的時(shí)候 F不能夠直接做到字符串的拼接"""
Q查詢
1.查詢賣出數(shù)大于100或者價(jià)格小于600的書籍:
res = models.Book.objects.filter(maichu__gt=100,price__lt=600) """filter括號(hào)內(nèi)多個(gè)參數(shù)是and關(guān)系""" from django.db.models import Q # res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600)) #Q逗號(hào)分割還是and關(guān)系 res = models.Book.objects.filter(Q(maichu__gt=100)|Q(price__lt=600)) ?# | or關(guān)系 # res = models.Book.objects.filter(~Q(maichu__gt=100)|Q(price__lt=600)) ?# ~ not關(guān)系 print(res) ?# <QuerySet []>
2、Q的高階用法 ?能夠?qū)⒉樵儣l件的左邊也變成字符串的形式
q = Q() q.connector = 'or' q.children.append(('maichu__gt',100)) q.children.append(('price__lt',600)) res = models.Book.objects.filter(q) ?# 默認(rèn)還是and關(guān)系 print(res)
?查看內(nèi)部sql語(yǔ)句的方式
方式1:queryset對(duì)象才能夠點(diǎn)擊query查看內(nèi)部的sql語(yǔ)句
res = models.User.objects.values_list('name','age') ? # <QuerySet [('jason', 18), ('egonPPP', 84)]> print(res.query)
方式2:所有的sql語(yǔ)句都能查看
# uptade等等沒有queryset對(duì)象的只需設(shè)置配置文件setting
LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'console':{'level':'DEBUG','class':'logging.StreamHandler',},},'loggers': {'django.db.backends': {'handlers': ['console'],'propagate': True,'level':'DEBUG',},} }