前言
Django框架功能齊全自帶數(shù)據(jù)庫(kù)操作功能,本文主要介紹Django的ORM框架
https://www.cnblogs.com/sss4/p/7070942.html
到目前為止舅锄,當(dāng)我們的程序涉及到數(shù)據(jù)庫(kù)相關(guān)操作時(shí)赃泡,我們一般都會(huì)這么搞:
創(chuàng)建數(shù)據(jù)庫(kù)师痕,設(shè)計(jì)表結(jié)構(gòu)和字段
使用 MySQLdb 來(lái)連接數(shù)據(jù)庫(kù)罩阵,并編寫數(shù)據(jù)訪問(wèn)層代碼
業(yè)務(wù)邏輯層去調(diào)用數(shù)據(jù)訪問(wèn)層執(zhí)行數(shù)據(jù)庫(kù)操作
ORM是什么望迎?:(在django中成榜,根據(jù)代碼中的類自動(dòng)生成數(shù)據(jù)庫(kù)的表也叫--code first)
ORM:Object Relational Mapping(關(guān)系對(duì)象映射)
類名對(duì)應(yīng)------》數(shù)據(jù)庫(kù)中的表名
類屬性對(duì)應(yīng)---------》數(shù)據(jù)庫(kù)里的字段
類實(shí)例對(duì)應(yīng)---------》數(shù)據(jù)庫(kù)表里的一行數(shù)據(jù)
obj.id ?obj.name.....類實(shí)例對(duì)象的屬性
Django orm的優(yōu)勢(shì):
Django的orm操作本質(zhì)上會(huì)根據(jù)對(duì)接的數(shù)據(jù)庫(kù)引擎,翻譯成對(duì)應(yīng)的sql語(yǔ)句意荤;所有使用Django開(kāi)發(fā)的項(xiàng)目無(wú)需關(guān)心程序底層使用的是MySQL啊片、Oracle、sqlite....玖像,如果數(shù)據(jù)庫(kù)遷移紫谷,只需要更換Django的數(shù)據(jù)庫(kù)引擎即可;
一、Django連接MySQL
1碴里、創(chuàng)建數(shù)據(jù)庫(kù) (注意設(shè)置 數(shù)據(jù)的字符編碼)
由于Django自帶的orm是data_first類型的ORM沈矿,使用前必須先創(chuàng)建數(shù)據(jù)庫(kù)
create database day70 default character set utf8 collate utf8_general_ci;
2、修改project中的settings.py文件中設(shè)置 ?連接 MySQL數(shù)據(jù)庫(kù)(Django默認(rèn)使用的是sqllite數(shù)據(jù)庫(kù))
DATABASES = {
? ? 'default': {
? ? 'ENGINE':'django.db.backends.mysql',
? ? 'NAME':'day70',
? ? 'USER':'eric',
? ? 'PASSWORD':'123123',
? ? 'HOST':'192.168.182.128',
? ? 'PORT':'3306',
? ? }
}
擴(kuò)展:查看orm操作執(zhí)行的原生SQL語(yǔ)句
在project中的settings.py文件增加
LOGGING = {
? ? 'version': 1,
? ? 'disable_existing_loggers': False,
? ? 'handlers': {
? ? ? ? 'console':{
? ? ? ? ? ? 'level':'DEBUG',
? ? ? ? ? ? 'class':'logging.StreamHandler',
? ? ? ? },
? ? },
? ? 'loggers': {
? ? ? ? 'django.db.backends': {
? ? ? ? ? ? 'handlers': ['console'],
? ? ? ? ? ? 'propagate': True,
? ? ? ? ? ? 'level':'DEBUG',
? ? ? ? },
? ? }
}
3咬腋、修改project 中的__init__py 文件設(shè)置 Django默認(rèn)連接MySQL的方式
import pymysql
pymysql.install_as_MySQLdb()
4羹膳、setings文件注冊(cè)APP
INSTALLED_APPS = [
? ? 'django.contrib.admin',
? ? 'django.contrib.auth',
? ? 'django.contrib.contenttypes',
? ? 'django.contrib.sessions',
? ? 'django.contrib.messages',
? ? 'django.contrib.staticfiles',
? ? 'app01.apps.App01Config',]
5、models.py創(chuàng)建表
6根竿、進(jìn)行數(shù)據(jù)遷移
6.1陵像、在winds cmd或者Linux shell的項(xiàng)目的manage.py目錄下執(zhí)行
python manage.py makemigrations #根據(jù)app下的migrations目錄中的記錄,檢測(cè)當(dāng)前model層代碼是否發(fā)生變化寇壳?python manage.py migrate#把orm代碼轉(zhuǎn)換成sql語(yǔ)句去數(shù)據(jù)庫(kù)執(zhí)行
python manage.py migrate --fake#只記錄變化醒颖,不提交數(shù)據(jù)庫(kù)操作
python manage.py inspectdb > models.py#檢查DB中已經(jīng)創(chuàng)建完畢的表結(jié)構(gòu),生成model.py
擴(kuò)展:修改表結(jié)構(gòu)之后常見(jiàn)報(bào)錯(cuò)
這個(gè)報(bào)錯(cuò):因?yàn)楸韯?chuàng)建之時(shí)壳炎,新增字段既沒(méi)有設(shè)置默認(rèn)值泞歉,也沒(méi)有設(shè)置新增字段可為空,去對(duì)應(yīng)原有數(shù)據(jù)導(dǎo)致匿辩;
2中解決方法:
1.設(shè)置新增字段可以為空
startdate = models.CharField(max_length=255, verbose_name="任務(wù)開(kāi)始時(shí)間",null=True, blank=True)? ? Handledate= models.CharField(max_length=255, verbose_name="開(kāi)始處理時(shí)間",null=True, blank=True)? ? Handledone= models.CharField(max_length=255, verbose_name="處理完畢時(shí)間",null=True, blank=True)? ? enddate= models.CharField(max_length=255, verbose_name="任務(wù)結(jié)束時(shí)間",null=True, blank=True)? ? WorkTime_cost=models.CharField(max_length=255,verbose_name='工作耗時(shí)',null=True, blank=True)
2.設(shè)置新增字段默認(rèn)值為 當(dāng)前時(shí)間
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt>>>timezone.now()
3.更多問(wèn)題
python manage.py makemigrations :把你寫在models中的代碼翻譯成增腰耙、刪、改的 SQL 語(yǔ)句铲球;
python manage.py migrate挺庞;講python manage.py makemigrations翻譯的SQL語(yǔ)句去數(shù)據(jù)庫(kù)執(zhí)行;?
python manage.py migrate --fake稼病;假設(shè) migrate 把所有SQL語(yǔ)句執(zhí)行成功了选侨;
我在使用Django構(gòu)建表結(jié)構(gòu)的時(shí)候很長(zhǎng)一段時(shí)間都是沒(méi)有了解以上3條語(yǔ)句的執(zhí)行意義,所有經(jīng)常在修改表結(jié)構(gòu)之后出現(xiàn)報(bào)錯(cuò)然走;
出現(xiàn)報(bào)錯(cuò)的原因:
無(wú)非就是? ?makemigrations翻譯的?SQL援制,跟數(shù)據(jù)庫(kù)里面真實(shí)的表結(jié)構(gòu) 相互沖突,增加、刪除不了表芍瑞、外鍵關(guān)系隘谣;
所以遇到報(bào)錯(cuò) 你應(yīng)該先把model中的代碼注釋掉-----》python manage.py migrate --fake------》python manage.py makemigrations
去數(shù)據(jù)庫(kù)把已經(jīng)存在的表、外鍵刪掉(確保數(shù)據(jù)庫(kù)目前的狀態(tài)啄巧,可以讓makemigrations翻譯出來(lái)的SQL語(yǔ)句在數(shù)據(jù)庫(kù)里執(zhí)行成功;然后migrate)--------》?python manage.py migrate掌栅;
7.設(shè)置pycharm可視化MySQL
三秩仆、ORM單表操作
0、orm操作前戲
orm使用方式:
orm操作可以使用類實(shí)例化猾封,obj.save的方式澄耍,也可以使用create()的形式
QuerySet數(shù)據(jù)類型介紹
QuerySet與惰性機(jī)制
所謂惰性機(jī)制:Publisher.objects.all()或者.filter()等都只是返回了一個(gè)QuerySet(查詢結(jié)果集對(duì)象),它并不會(huì)馬上執(zhí)行sql,而是當(dāng)調(diào)用QuerySet的時(shí)候才執(zhí)行齐莲。
QuerySet特點(diǎn):
? ? ?? <1>? 可迭代的?
? ? ?? <2>? 可切片
?<3>惰性計(jì)算和緩存機(jī)制
def queryset(request):
? ? books=models.Book.objects.all()[:10]#切片 應(yīng)用分頁(yè)books = models.Book.objects.all()[::2]
? ? book= models.Book.objects.all()[6]#索引print(book.title)
? ? forobjinbooks:#可迭代print(obj.title)
? ? books=models.Book.objects.all()#惰性計(jì)算--->等于一個(gè)生成器痢站,不應(yīng)用books不會(huì)執(zhí)行任何SQL操作# query_set緩存機(jī)制1次數(shù)據(jù)庫(kù)查詢結(jié)果query_set都會(huì)對(duì)應(yīng)一塊緩存,再次使用該query_set時(shí)选酗,不會(huì)發(fā)生新的SQL操作阵难;#這樣減小了頻繁操作數(shù)據(jù)庫(kù)給數(shù)據(jù)庫(kù)帶來(lái)的壓力;authors=models.Author.objects.all()
? ? forauthorin? authors:
? ? ? ? print(author.name)
? ? print('-------------------------------------')
? ? models.Author.objects.filter(id=1).update(name='張某')
? ? forauthorin? authors:
? ? ? ? print(author.name)
? ? #但是有時(shí)候取出來(lái)的數(shù)據(jù)量太大會(huì)撐爆緩存,可以使用迭代器優(yōu)雅得解決這個(gè)問(wèn)題芒填;? ? models.Publish.objects.all().iterator()
? ? returnHttpResponse('OK')
增加和查詢操作
增
def orm(request):
? ? orm2添加一條記錄的方法
? ? 單表
? ? 1呜叫、表.objects.create()
? ? models.Publish.objects.create(name='浙江出版社',addr="浙江.杭州")
? ? models.Classify.objects.create(category='武俠')
? ? models.Author.objects.create(name='金庸',sex='男',age=89,university='東吳大學(xué)')
? ? 2、類實(shí)例化:obj=類(屬性=XX) obj.save()
? ? obj=models.Author(name='吳承恩',age=518,sex='男',university='龍溪學(xué)院')
? ? obj.save()
? ? 1對(duì)多
? ? 1殿衰、表.objects.create()
? ? models.Book.objects.create(title='笑傲江湖',price=200,date=1968,classify_id=6, publish_id=6)
? ? 2朱庆、類實(shí)例化:obj=類(屬性=X,外鍵=obj)obj.save()
? ? classify_obj=models.Classify.objects.get(category='武俠')
? ? publish_obj=models.Publish.objects.get(name='河北出版社')
? ? 注意以上獲取得是和 book對(duì)象 向關(guān)聯(lián)的(外鍵)的對(duì)象
? ? book_obj=models.Book(title='西游記',price=234,date=1556,classify=classify_obj,publish=publish_obj)
? ? book_obj.save()
? ? 多對(duì)多
? ? 如果兩表之間存在雙向1對(duì)N關(guān)系,就無(wú)法使用外鍵來(lái)描述其關(guān)系了闷祥;
? ? 只能使用多對(duì)多的方式娱颊,新增第三張表關(guān)系描述表;
? ? book=models.Book.objects.get(title='笑傲江湖')
? ? author1=models.Author.objects.get(name='金庸')
? ? author2=models.Author.objects.get(name='張根')
? ? book.author.add(author1,author2)
? ? 書籍和作者是多對(duì)多關(guān)系凯砍,
? ? 切記:如果兩表之間存在多對(duì)多關(guān)系箱硕,例如書籍相關(guān)的所有作者對(duì)象集合,作者也關(guān)聯(lián)的所有書籍對(duì)象集合
? ? book=models.Book.objects.get(title='西游記')
? ? author=models.Author.objects.get(name='吳承恩')
? ? author2 = models.Author.objects.get(name='張根')
? ? book.author.add(author,author2)
? ? #add()? 添加#clear() 清空#remove() 刪除某個(gè)對(duì)象returnHttpResponse('OK')
根據(jù)條件判斷果覆,增加颅痊?更新?
# 根據(jù)user=user去查找局待,如果找到更新 如果沒(méi)有找到創(chuàng)建defaults={} 中的數(shù)據(jù)tk = gen_tcoken(username)
? ? ? ? ? ? models.Token.objects.update_or_create(user=user, defaults={'token': tk})
刪
級(jí)聯(lián)刪除
為防止讀者跑路斑响,不再贅述!
改
# 修改方式1 update()models.Book.objects.filter(id=1).update(price=3)
? ? #修改方式2 obj.save() book_obj=models.Book.objects.get(id=1)
? ? book_obj.price=5? ? book_obj.save()
查
def ormquery(request):
? ? books=models.Book.objects.all()#------query_set對(duì)象集合 [對(duì)象1钳榨、對(duì)象2舰罚、.... ]books=models.Book.objects.filter(id__gt=2,price__lt=100)
? ? book=models.Book.objects.get(title__endswith='金')#---------單個(gè)對(duì)象,沒(méi)有找到會(huì)報(bào)錯(cuò)book1 = models.Book.objects.filter(title__endswith='金').first()
? ? book2 = models.Book.objects.filter(title__icontains='瓶').last()
? ? books=models.Book.objects.values('title','price',#-------query_set字典集合 [{一條記錄},{一條記錄} ]'publish__name',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'date',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'classify__category',#切記 正向連表:外鍵字段___對(duì)應(yīng)表字段'author__name',#反向連表: 小寫表名__對(duì)應(yīng)表字段'author__sex',#區(qū)別:正向 外鍵字段__薛耻,反向 小寫表名__'author__age',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'author__university')
? ? books=models.Book.objects.values('title','publish__name').distinct()?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #exclude 按條件排除营罢。。饼齿。#distinct()去重, exits()查看數(shù)據(jù)是否存在饲漾? 返回 true 和falsea=models.Book.objects.filter(title__icontains='金').?
? ? returnHttpResponse('OK')
連表查詢
反向連表查詢:
? ? 1、通過(guò)object的形式反向連表缕溉, obj.小寫表名_set.all()
? ? publish=models.Publish.objects.filter(name__contains='湖南').first()
? ? books=publish.book_set.all()
? ? forbookin? books:
? ? ? ? print(book.title)
? ? 通過(guò)object的形式反向綁定外鍵關(guān)系
? ? authorobj = models.Author.objects.filter(id=1).first()
? ? objects = models.Book.objects.all()
? ? authorobj.book_set.add(*objects)
? ? authorobj.save()
? ? 2考传、通過(guò)values雙下滑線的形式,objs.values("小寫表名__字段")
? ? 注意對(duì)象集合調(diào)用values()证鸥,正向查詢是外鍵字段__XX,而反向是小寫表名__YY看起來(lái)比較容易混淆僚楞;
? ? books=models.Publish.objects.filter(name__contains='湖南').values('name','book__title')
? ? authors=models.Book.objects.filter(title__icontains='我的').values('author__name')
? ? print(authors)
? ? fifter()也支持__小寫表名語(yǔ)法進(jìn)行連表查詢:在publish標(biāo)查詢 出版過(guò)《笑傲江湖》的出版社
? ? publishs=models.Publish.objects.filter(book__title='笑傲江湖').values('name')
? ? print(publishs)
? ? 查詢誰(shuí)(哪位作者)出版過(guò)的書價(jià)格大于200元
? ? authors=models.Author.objects.filter(book__price__gt=200).values('name')
? ? print(authors)
? ? 通過(guò)外鍵字段正向連表查詢勤晚,出版自保定的書籍;
? ? city=models.Book.objects.filter(publish__addr__icontains='保定').values('title')
? ? print(city)
1泉褐、基本操作
# 增## models.Tb1.objects.create(c1='xx', c2='oo')? 增加一條數(shù)據(jù)赐写,可以接受字典類型數(shù)據(jù) **kwargs# obj = models.Tb1(c1='xx', c2='oo')# obj.save()# 查## models.Tb1.objects.get(id=123)? ? ? ? # 獲取單條數(shù)據(jù),不存在則報(bào)錯(cuò)(不建議)# models.Tb1.objects.all()? ? ? ? ? ? ? # 獲取全部# models.Tb1.objects.filter(name='seven') # 獲取指定條件的數(shù)據(jù)# 刪## models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數(shù)據(jù)# 改# models.Tb1.objects.filter(name='seven').update(gender='0')? # 將指定條件的數(shù)據(jù)更新膜赃,均支持 **kwargs# obj = models.Tb1.objects.get(id=1)# obj.c1 = '111'# obj.save()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 修改單條數(shù)據(jù)基本操作
2挺邀、進(jìn)階操作(了不起的雙下劃線)
利用雙下劃線將字段和對(duì)應(yīng)的操作連接起來(lái)
# 獲取個(gè)數(shù)## models.Tb1.objects.filter(name='seven').count()
# 大于,小于
## models.Tb1.objects.filter(id__gt=1)? ? ? ? ? ? ? # 獲取id大于1的值#?
models.Tb1.objects.filter(id__gte=1)? ? ? ? ? # 獲取id大于等于1的值#?
models.Tb1.objects.filter(id__lt=10)? ? ? ? ? ? # 獲取id小于10的值#?
models.Tb1.objects.filter(id__lte=10)? ? ? ? ? ? # 獲取id小于10的值#
?models.Tb1.objects.filter(id__lt=10, id__gt=1)? #獲取id大于1 且 小于10的值#?
in## 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# isnull# Entry.objects.filter(pub_date__isnull=True)# contains#
# models.Tb1.objects.filter(name__contains="ven")
# models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
# models.Tb1.objects.exclude(name__icontains="ven")
# range## models.Tb1.objects.filter(id__range=[1, 2])? # 范圍bettwen and#?
其他類似## startswith,istartswith, endswith, iendswith,# order by#
# models.Tb1.objects.filter(name='seven').order_by('id')? ? #
?asc# models.Tb1.objects.filter(name='seven').order_by('-id')? #
?desc# group by## from django.db.models import Count, Min, Max, Sum
# models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
# SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"# limit 躺坟、offset#
# models.Tb1.objects.all()[10:20]# regex正則匹配沦补,iregex 不區(qū)分大小寫#
# Entry.objects.get(title__regex=r'^(An?|The) +')# Entry.objects.get(title__iregex=r'^(an?|the) +')# date#
# Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))# year## Entry.objects.filter(pub_date__year=2005)# Entry.objects.filter(pub_date__year__gte=2005)#?
month## Entry.objects.filter(pub_date__month=12)# Entry.objects.filter(pub_date__month__gte=6)# day## Entry.objects.filter(pub_date__day=3)# Entry.objects.filter(pub_date__day__gte=3)# week_day## Entry.objects.filter(pub_date__week_day=2)# Entry.objects.filter(pub_date__week_day__gte=2)# hour## Event.objects.filter(timestamp__hour=23)# Event.objects.filter(time__hour=5)# Event.objects.filter(timestamp__hour__gte=12)# minute## Event.objects.filter(timestamp__minute=29)# Event.objects.filter(time__minute=46)# Event.objects.filter(timestamp__minute__gte=29)# second## Event.objects.filter(timestamp__second=31)# Event.objects.filter(time__second=2)# Event.objects.filter(timestamp__second__gte=31)進(jìn)階操作
3、其他操作(執(zhí)行原生SQL)
# 執(zhí)行原生SQL? 1.執(zhí)行自定義SQL# from django.db import connection, connections# cursor = connection.cursor()? # cursor = connections['default'].cursor()# cursor.execute("""SELECT * from auth_user where id = %s""", [1])# row = cursor.fetchone()2.使用extra方法## extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)#? ? Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))#? ? Entry.objects.extra(where=['headline=%s'], params=['Lennon'])#? ? Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])#? ? Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])3.使用raw方法
解釋:執(zhí)行原始sql并返回模型
說(shuō)明:依賴model多用于查詢
用法:
book = Book.objects.raw("select * from hello_book")
foritemin book:
print(item.title)
https://www.cnblogs.com/413xiaol/p/6504856.html
? ? # F## from django.db.models import F# models.Tb1.objects.update(num=F('num')+1)# Q## 方式一:# Q(nid__gt=10)# Q(nid=8) | Q(nid__gt=10)# Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')# 方式二:# con = Q()# q1 = Q()# q1.connector = 'OR'# q1.children.append(('id', 1))# q1.children.append(('id', 10))# q1.children.append(('id', 9))# q2 = Q()# q2.connector = 'OR'# q2.children.append(('c1', 1))# q2.children.append(('c1', 10))# q2.children.append(('c1', 9))# con.add(q1, 'AND')# con.add(q2, 'AND')## models.Tb1.objects.filter(con)