ORM操作
單表使用ORM對(duì)數(shù)據(jù)庫(kù)的增刪改查
ORM與數(shù)據(jù)庫(kù)的對(duì)應(yīng)
類? ?==> 表
對(duì)象 ? ==> 記錄
屬性 ==> 字段
from django.db import modelsclass Publisher(models.Model):id = models.AutoField(primary_key=True)name = models.CharField(max_length=32, unique=True)class Book(models.Model):id = models.AutoField(primary_key=True)title = models.CharField(max_length=32, unique=True)publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)# publisher為外鍵,ORM自動(dòng)將publisher后面加上_id作為字段傳給數(shù)據(jù)庫(kù),可以使用book_obj.publisher_id找到書(shū)籍對(duì)象對(duì)應(yīng)的出版社的id,這是直接操作數(shù)據(jù)庫(kù)的# publisher作為ORM中BOOK類的屬性,可以通過(guò)book_obj.publisher找到書(shū)籍對(duì)象對(duì)應(yīng)的出版社對(duì)象,這仍然是通過(guò)ORM操作數(shù)據(jù)庫(kù)def __repr__(self):return "<Book object: {} >".format(self.title)class Author(models.Model):name = models.CharField(max_length=32, unique=True)books = models.ManyToManyField('Book')def __repr__(self):return "<Author object: {} >".format(self.name)__str__ = __repr__增:普通表: models.Publisher.objects.create(name='xxx') 帶外鍵的表: models.Book.objects.create(name='xxx',publisher=publisher_obj)models.Book.objects.create(name='xxx',publisher_id=publisher_obj.id)帶多對(duì)多的表: author_obj = models.Author.objects.create(name='xxxxx')author_obj.books.set([1,3,4])刪除:對(duì)象列表.delete()對(duì)象.delete()修改:普通表: pub_obj.name='xxxxx'pub_obj.save()帶外鍵的表: book_obj.title = 'xxxxx'book_obj.publisher = publisher_obj 或book_obj.publisher_id = publisher_obj.id 或 book_obj.publisher_id = 'id的數(shù)值'(推薦這種寫(xiě)法,直接操作數(shù)據(jù)庫(kù))book_obj.save()帶多對(duì)多的表 author_obj.name = 'xxx'author_obj.save() author_obj.books.set([1,3,4])查:普通字段: pub_obj.id外鍵字段: book_obj.publisher —— 》 關(guān)聯(lián)的出版社對(duì)象book_obj.publisher_id —— 》 關(guān)聯(lián)的出版社對(duì)象的id多對(duì)多字段: author_ob.books —— 》 管理對(duì)象 author_ob.books.all() —— 》 作者關(guān)聯(lián)的所有書(shū)籍對(duì)象列表?
?
?
常用字段?
AutoField
自增的整形字段,必填參數(shù)primary_key=True,則成為數(shù)據(jù)庫(kù)的主鍵。無(wú)該字段時(shí),django自動(dòng)創(chuàng)建。
一個(gè)model不能有兩個(gè)AutoField字段。
IntegerField
一個(gè)整數(shù)類型。數(shù)值的范圍是?-2147483648 ~ 2147483647。
CharField
字符類型,必須提供max_length參數(shù)。max_length表示字符的長(zhǎng)度。
DateField
日期類型,日期格式為YYYY-MM-DD,相當(dāng)于Python中的datetime.date的實(shí)例。
參數(shù):
- auto_now:每次修改時(shí)修改為當(dāng)前日期時(shí)間。
- auto_now_add:新創(chuàng)建對(duì)象時(shí)自動(dòng)添加當(dāng)前日期時(shí)間。
auto_now和auto_now_add和default參數(shù)是互斥的,不能同時(shí)設(shè)置。
DatetimeField
?
復(fù)制代碼AutoField(Field)- int自增列,必須填入?yún)?shù) primary_key=TrueBigAutoField(AutoField)- bigint自增列,必須填入?yún)?shù) primary_key=True注:當(dāng)model中如果沒(méi)有自增列,則自動(dòng)會(huì)創(chuàng)建一個(gè)列名為id的列from django.db import modelsclass 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 ~ 32767PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正小整數(shù) 0 ~ 32767IntegerField(Field)- 整數(shù)列(有符號(hào)的) -2147483648 ~ 2147483647PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正整數(shù) 0 ~ 2147483647BigIntegerField(IntegerField):- 長(zhǎng)整型(有符號(hào)的) -9223372036854775808 ~ 9223372036854775807BooleanField(Field)- 布爾值類型NullBooleanField(Field):- 可以為空的布爾值CharField(Field)- 字符類型- 必須提供max_length參數(shù), max_length表示字符長(zhǎng)度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)證 URLSlugField(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.FileSystemStorageImageField(FileField)- 字符串,路徑保存在數(shù)據(jù)庫(kù),文件上傳到指定目錄- 參數(shù):upload_to = "" 上傳文件的保存路徑storage = None 存儲(chǔ)組件,默認(rèn)django.core.files.storage.FileSystemStoragewidth_field=None, 上傳圖片的高度保存的數(shù)據(jù)庫(kù)字段名(字符串)height_field=None 上傳圖片的寬度保存的數(shù)據(jù)庫(kù)字段名(字符串)DateTimeField(DateField)- 日期+時(shí)間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]DateField(DateTimeCheckMixin, Field)- 日期格式 YYYY-MM-DDTimeField(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)制類型 詳細(xì)字段類型?
#自定義一個(gè)char類型字段: class MyCharField(models.Field):"""自定義的char類型的字段類"""def __init__(self, max_length, *args, **kwargs):self.max_length = max_lengthsuper(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)def db_type(self, connection):"""限定生成數(shù)據(jù)庫(kù)表的字段類型為char,長(zhǎng)度為max_length指定的值"""return 'char(%s)' % self.max_length #使用自定義char類型字段: class Class(models.Model):id = models.AutoField(primary_key=True)title = models.CharField(max_length=25)# 使用自定義的char類型的字段cname = MyCharField(max_length=25)?
?
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ù)中字段【年】部分是否可以建立唯一索引verbose_name Admin中顯示的字段名稱blank Admin中是否允許用戶輸入為空editable Admin中是否可以編輯help_text Admin中該字段的提示信息choices Admin中顯示選擇框的內(nèi)容,用不變動(dòng)的數(shù)據(jù)放在內(nèi)存中從而避免跨表操作如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)error_messages 自定義錯(cuò)誤信息(字典類型),從而定制想要顯示的錯(cuò)誤信息;字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date如:{'null': "不能為空.", 'invalid': '格式錯(cuò)誤'}validators 自定義錯(cuò)誤驗(yàn)證(列表類型),從而定制想要的驗(yàn)證規(guī)則from django.core.validators import RegexValidatorfrom django.core.validators import EmailValidator,URLValidator,DecimalValidator,\MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator如:test = models.CharField(max_length=32,error_messages={'c1': '優(yōu)先錯(cuò)信息1','c2': '優(yōu)先錯(cuò)信息2','c3': '優(yōu)先錯(cuò)信息3',},validators=[RegexValidator(regex='root_\d+', message='錯(cuò)誤了', code='c1'),RegexValidator(regex='root_112233\d+', message='又錯(cuò)誤了', code='c2'),EmailValidator(message='又錯(cuò)誤了', code='c3'), ])字段參數(shù) 字段參數(shù)Model Meta參數(shù)
app01 下的models.pyclass UserInfo(models.Model):nid = models.AutoField(primary_key=True)username = models.CharField(max_length=32)class Meta:# 數(shù)據(jù)庫(kù)中生成的表名稱 默認(rèn) app名稱 + 下劃線 + 類名db_table = "table_name"# admin中顯示的表名稱verbose_name = '個(gè)人信息'# verbose_name加sverbose_name_plural = '所有用戶信息'# 聯(lián)合索引 index_together = [("pub_date", "deadline"), # 應(yīng)為兩個(gè)存在的字段 ]# 聯(lián)合唯一索引unique_together = (("driver", "restaurant"),) # 應(yīng)為兩個(gè)存在的字段
普通索引:僅加速查詢
唯一索引:加速查詢 + 列值唯一(可以有null)
主鍵索引:加速查詢 + 列值唯一 + 表中只有一個(gè)(不可以有null)
組合索引:多列值組成一個(gè)索引,
? ? ? ? ? ? ? 專門用于組合搜索,其效率大于索引合并
全文索引:對(duì)文本的內(nèi)容進(jìn)行分詞,進(jìn)行搜索?
查詢的13條命令?
不必非在app下的models進(jìn)行ORM操作,可以在項(xiàng)目目錄下新建文件夾,新建py文件進(jìn)行ORM操作
我們?cè)赿jango中運(yùn)行項(xiàng)目都是通過(guò)manage.py來(lái)完成的,下面的代碼設(shè)置的一些環(huán)境在manage.py中也有,可以直接粘過(guò)來(lái)
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings") # orm_practice是當(dāng)前的項(xiàng)目名import djangodjango.setup()from app01 import models# all 獲取所有對(duì)象 ——》 QuerySetret = models.Person.objects.all()# get 獲取單獨(dú)的對(duì)象 ——》 對(duì)象# 找不到或者找到多個(gè)就報(bào)錯(cuò)ret= models.Person.objects.get(id=1,name='阿旭')# filter 過(guò)濾 獲取所有滿足條件的對(duì)象 ——》QuerySetret = models.Person.objects.filter(id=1)# exclude 獲取不滿足條件的所有對(duì)象ret = models.Person.objects.exclude(id=1)# values ——》QuerySet 元素是字典# 不寫(xiě)參數(shù) 默認(rèn)所有字段的名字和值# 寫(xiě)參數(shù) 拿到指定字段的名字和值ret = models.Person.objects.all().values('id','name')ret = models.Person.objects.values('id','name')# values_list ——》QuerySet 元素是元組 只有值沒(méi)有字段名# 不寫(xiě)參數(shù) 默認(rèn)所有字段值# 寫(xiě)參數(shù) 拿到指定字段值ret = models.Person.objects.values_list('name','id')# print(ret)# for i in ret :# print(i,type(i))# reverse 對(duì)已經(jīng)排序的QuerySet進(jìn)行反轉(zhuǎn)ret = models.Person.objects.all().reverse()# distinct 去重 ——》QuerySet# count 對(duì)QuerySet中的元素進(jìn)行計(jì)數(shù)ret = models.Person.objects.filter(id=100).count()# first 取QuerySet中的第一個(gè)元素ret = models.Person.objects.all().first()# last 取QuerySet中的最后一個(gè)元素ret = models.Person.objects.all().last()ret = models.Person.objects.values_list().last()ret = models.Person.objects.filter(id=100).first()# exists 判斷查詢結(jié)果是否有值ret = models.Person.objects.filter(id=100).exists()# print(ret)# order_by 按字段進(jìn)行排序 ——》QuerySetret =models.Person.objects.order_by('age')print(ret) """ 返回是QuerySet的方法 1. all() 2. filter() 3. values() 4. values_list() 5. order_by() 6. distinct() 7. reverse() 8. exclude()返回是對(duì)象 1. get() 2. first() 3. last()返回是布爾值 1. exists()返回是數(shù)字 1. count()"""?
?
?單表的雙下劃線
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")import djangodjango.setup()from app01 import modelsret = models.Person.objects.filter(id__lt=3) # less thanret = models.Person.objects.filter(id__gt=3) # great than ret = models.Person.objects.filter(id__gte=3) # great than equelret = models.Person.objects.filter(id__lte=3) # great than equelret = models.Person.objects.filter(id__gte=3, id__lte=5)ret = models.Person.objects.exclude(id__gt=5)ret = models.Person.objects.filter(id__in=[1, 3, 5])ret = models.Person.objects.exclude(id__in=[1, 3, 5])ret = models.Person.objects.filter(id__gte=1, id__lte=100) #并且的關(guān)系ret = models.Person.objects.filter(id__range=[1, 5]) # id范圍在1-5包括1和5ret = models.Person.objects.filter(name__contains='A') # name包含'A'類似于sql語(yǔ)句中的likeret = models.Person.objects.filter(name__icontains='a') # name中包含'A'或'a',不區(qū)分大小寫(xiě) ret = models.Person.objects.filter(name__istartswith='a') # 以'a'開(kāi)頭ret = models.Person.objects.filter(name__endswith='x') # 以'x'結(jié)尾 ret = models.Person.objects.filter(birth__year='2018') # 篩選年份為'2018'日期的對(duì)象ret = models.Person.objects.filter(birth__month='09') # 篩選月份為'09'日期的對(duì)象ret = models.Person.objects.filter(name__isnull=True) # 篩選名字不為空的對(duì)象print(ret)跨表查詢(連表查詢)中的雙下劃線表示另一個(gè)關(guān)聯(lián)表(外鍵關(guān)聯(lián)或多對(duì)多關(guān)聯(lián))中的字段.
如ret= models.Book.objects.filter(publisher__name='沙河出版社')? ??publisher__name表示publisher表中的name字段? ?這個(gè)語(yǔ)句的意思是篩選出所有 出版社為沙河出版社出版的書(shū)籍
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")import djangodjango.setup()from app01 import models# 正向查詢 book ——》 publisher# 基于對(duì)象查詢book_obj = models.Book.objects.get(id=1)print(book_obj.id)print(book_obj.title)print(book_obj.publisher_id)print(book_obj.publisher_id) # 關(guān)聯(lián)的出版社對(duì)象print(book_obj.publisher.id) # 關(guān)聯(lián)的出版社對(duì)象print(book_obj.publisher.name)# 基于字段查詢ret= models.Book.objects.filter(publisher__name='沙河出版社')ret= models.Book.objects.filter(publisher_id=1)print(ret)# 反向查詢 publisher ——》 book# 基于對(duì)象的查詢# 1 —— 》 多 表名小寫(xiě)_set ——》 管理對(duì)象 .all() 出版社關(guān)聯(lián)的所有書(shū)籍對(duì)象pub_obj = models.Publisher.objects.first()# 表名小寫(xiě)_set ,注意是表名小寫(xiě)_set 而不是子表(多對(duì)一中的多)的外鍵名_set ret = pub_obj.book_set.all() print(pub_obj.book_set,type(pub_obj.book_set)) book_set是外鍵反向查詢的管理對(duì)象print(ret)class Book(models.Model):title = models.CharField(max_length=32)publisher = models.ForeignKey('Publisher',related_name='books', # 關(guān)聯(lián)名字# related_query_name='xx', #關(guān)聯(lián)查詢名字on_delete=models.CASCADE, null=True)# Class Book中指定了related_name books# print(pub_obj.books.all())# 基于字段的查詢#1,不指定related_name和related_query_nameret = models.Publisher.objects.filter(book__title='跟太亮學(xué)開(kāi)車') 表名#2,指定related_name 不指定related_query_nameret = models.Publisher.objects.filter(books__title='跟太亮學(xué)開(kāi)車') 使用related_name 指定的名字 'books'#3,指定related_name和related_query_nameret = models.Publisher.objects.filter(xx__title='跟太亮學(xué)開(kāi)車') 使用related_query_name 指定的名字 'xx'print(ret)?
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")import djangodjango.setup()from app01 import modelsauthor_obj = models.Author.objects.get(id=1)# print(author_obj.books.all()) books是多對(duì)多管理對(duì)象 # 多對(duì)多中的 creat() add() remove() clear()# create()# author_obj.books.create(title='戴綠與嫂子的故事',publisher_id=1)# 1. 創(chuàng)建書(shū)籍對(duì)象(與出版社進(jìn)行關(guān)聯(lián))# 2. 該對(duì)象和作者進(jìn)行關(guān)聯(lián)# add()book_list = models.Book.objects.filter(id__in=[1,6,8,9])author_obj.books.add(*books_list) # 增加作者對(duì)應(yīng)的書(shū)籍 可以寫(xiě)id 可以寫(xiě)對(duì)象,book_list是對(duì)象列表,需要用*打散# set()author_obj.books.set([1,6,8,9]) # 用書(shū)籍id設(shè)置作者對(duì)應(yīng)的書(shū)籍 author_obj.books.set(books)author_obj.books.remove(*books)author_obj.books.clear()# 一對(duì)多中的 creat() remove() clear()pub_obj= models.Publisher.objects.first()pub_obj.book_set book_set是反向查詢的管理對(duì)象pub_obj.books.create(title='跟老男孩學(xué)思想')pub_obj = models.Publisher.objects.get(id=1)# 一對(duì)多的管理對(duì)象remove不能使用id 使用對(duì)象pub_obj.books.remove(models.Book.objects.get(id=5))pub_obj.books.clear() # 清空關(guān)聯(lián)的書(shū)籍聚合和分組
聚合:aggregate(*args,**kwargs)
通過(guò)對(duì)QuerySet進(jìn)行計(jì)算,返回一個(gè)聚合值的字典。aggregate()中每一個(gè)參數(shù)都指定一個(gè)包含在字典中的返回值。即在查詢集上生成聚合。
聚合的結(jié)果不包含原來(lái)表中的字段,aggregate()是QuerySet 的一個(gè)終止子句,只能在最后寫(xiě)他
分組:annotate(*args,**kwargs):
可以通過(guò)計(jì)算查詢結(jié)果中每一個(gè)對(duì)象所關(guān)聯(lián)的對(duì)象集合,從而得出總計(jì)值(也可以是平均值或總和),即為查詢集的每一項(xiàng)生成聚合。
對(duì)分組后的每一組進(jìn)行查詢計(jì)算,然后將結(jié)果作為注釋添加到表每行的數(shù)據(jù)中
簡(jiǎn)單看下用法,詳細(xì)用法見(jiàn)下面的練習(xí)代碼
#查詢alex出的書(shū)的總價(jià)格 Book.object.filter(authors__name='alex').aggregate(Sum('price')) #查詢各個(gè)作者出的書(shū)的總價(jià)格,這里就涉及到分組了,分組條件是anthors__name Book.object.values('authors__name').annotate(Sum('price')) #查詢各個(gè)出版社最便宜的書(shū)價(jià)是多少 Book.object.values('publisher__name').annotate(Min('price'))F查詢和Q查詢
??
#僅僅靠單一的關(guān)鍵字參數(shù)查詢已經(jīng)很難滿足查詢要求。此時(shí)Django為我們提供了F查詢和Q查詢 # F 使用查詢條件的值,專門取對(duì)象中某列值的操作 models.Tb1.objects.update(num=F('num')+1) # 將num加1后重新賦值給num # Q 構(gòu)建搜索條件 models.Book.objects.filter(Q(id__lt=3)|Q(id__gt=5)).values() # filter中兩個(gè)條件以逗號(hào)分隔是and的關(guān)系,使用Q查詢可以有或的關(guān)系import os if __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")import djangodjango.setup()from app01 import modelsfrom django.db.models import F,Qret = models.Book.objects.filter(sale__gt=50).values() # 一個(gè)字段的比較不用使用F查詢r(jià)et = models.Book.objects.filter(sale__gte=F('kucun')+30).values() # 兩個(gè)字段的值進(jìn)行比較需要使用F查詢 ret = models.Book.objects.filter(~Q(id__lt=3)|Q(id__gt=5)).values() # ~是取反 和!意義一樣for i in ret:print(i)# updata()和save()的區(qū)別,updata只修改條件內(nèi)的表的字段,save是把所有的字段都再保存一遍# models.Book.objects.all().update(sale=100)# book_obj = models.Book.objects.get(id=1)# book_obj.sale=0# book_obj.save()# models.Book.objects.all().update(sale=(F('sale')+10)*2)詳細(xì)說(shuō)明
# F 使用查詢條件的值,專門取對(duì)象中某列值的操作from django.db.models import Fmodels.Tb1.objects.update(num=F('num')+1)# Q 構(gòu)建搜索條件from django.db.models import Q# 1 Q對(duì)象(django.db.models.Q)可以對(duì)關(guān)鍵字參數(shù)進(jìn)行封裝,從而更好地應(yīng)用多個(gè)查詢q1 = models.Book.objects.filter(Q(title__startswith='P')).all()print(q1) # [<Book: Python>, <Book: Perl>]# 2、可以組合使用&,|操作符,當(dāng)一個(gè)操作符是用于兩個(gè)Q的對(duì)象,它產(chǎn)生一個(gè)新的Q對(duì)象。Q(title__startswith='P') | Q(title__startswith='J')# 3、Q對(duì)象可以用~操作符放在前面表示否定,也可允許否定與不否定形式的組合Q(title__startswith='P') | ~Q(pub_date__year=2005)# 4、應(yīng)用范圍:# Each lookup function that takes keyword-arguments (e.g. filter(),# exclude(), get()) can also be passed one or more Q objects as# positional (not-named) arguments. If you provide multiple Q object# arguments to a lookup function, the arguments will be “AND”ed# together. For example:Book.objects.get(Q(title__startswith='P'),Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))# sql:# SELECT * from polls WHERE title LIKE 'P%'# AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')# import datetime# e=datetime.date(2005,5,6) #2005-05-06# 5、Q對(duì)象可以與關(guān)鍵字參數(shù)查詢一起使用,不過(guò)一定要把Q對(duì)象放在關(guān)鍵字參數(shù)查詢的前面。# 正確:Book.objects.get(Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),title__startswith='P')# 錯(cuò)誤:Book.objects.get(question__startswith='P',Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))事務(wù)
?通過(guò)事務(wù)我們可以把兩件或者兩件以上的ORM操作組成一個(gè)原子,這幾件事要么都成功,一旦有一個(gè)失敗了,那么全部不執(zhí)行,即使執(zhí)行過(guò)了也要回滾回去
比如,我們操作數(shù)據(jù)庫(kù)進(jìn)行轉(zhuǎn)賬操作,A向B轉(zhuǎn)賬分為兩步,A的賬戶扣錢,B的賬戶加錢,這兩件事必須都成功,或者都失敗
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")import djangodjango.setup()from app01 import modelstry:from django.db import transaction # 導(dǎo)入從django事務(wù)模塊import datetimewith transaction.atomic():new_publisher = models.Publisher.objects.create(name="火星出版社") # 這條語(yǔ)句單獨(dú)是可以成功的models.Book.objects.create(title="橘子物語(yǔ)",publisher_id=100) # 指定一個(gè)不存在的出版社id,這條語(yǔ)句會(huì)報(bào)錯(cuò),所以作為整體,事務(wù)內(nèi)所有語(yǔ)句都不會(huì)執(zhí)行except Exception as e:print(str(e))
ORM查詢練習(xí)
簡(jiǎn)單說(shuō)明:? ? publisher? ? ?字段? ?id? ? name? ?city
book? ? ? ? ? ? 字段? ?id? ? title? ? publish_date? ? ?price? ? ?memo? ? ? publisher(外鍵關(guān)聯(lián)了publisher)? ? author(多對(duì)多管理對(duì)象,關(guān)聯(lián)了作者)
author? ? ? ? ? 字段? ? id? ?name? ? age? ? ? phone
import osos.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_homework.settings") import djangodjango.setup()from app01 import models from django.db.models import Q, Max, Count# 查找所有書(shū)名里包含金老板的書(shū) ret = models.Book.objects.filter(title__contains='金老板')# 查找出版日期是2018年的書(shū) ret = models.Book.objects.filter(publish_date__year=2018)# 查找價(jià)格大于10元的書(shū) ret = models.Book.objects.filter(price__gt=10)# 查找memo字段是空的書(shū) # -----字段為空包括空字符串和null , null和空字符串并不是一回事 ret = models.Book.objects.filter(Q(memo='') | Q(memo__isnull=True))# 查找名字以沙河開(kāi)頭的出版社 # ----distinct去重,有兩個(gè)名字相同但是id不同的沙河出版社對(duì)象,所以這個(gè)去重并不能給對(duì)象去重,需要先使用values()取出出版社的名字,這樣變成字典后再對(duì)名字進(jìn)行去重 ret = models.Publisher.objects.filter(name__startswith='沙河').values('name').distinct()# 查找“沙河出版社”出版的所有書(shū)籍 # ----連表查詢,使用另一個(gè)表的屬性時(shí)要使用雙下劃線 ret = models.Book.objects.filter(publisher__name='沙河出版社')# 查找每個(gè)出版社出版價(jià)格最高的書(shū)籍價(jià)格 # ----annotate分組聚合,分組后就一定要使用聚合函數(shù),annotate在官方文檔的意思是注釋的意思,給表中每行的數(shù)據(jù)添加注釋 # ----對(duì)annotate前的表進(jìn)行分組,annotate前有values的話,是以values中的值進(jìn)行分組,沒(méi)有values默認(rèn)以annotate前表的id進(jìn)行分組 ret = models.Publisher.objects.annotate(max=Max('book__price')).values('name', 'max', )ret = models.Book.objects.values('publisher__name').annotate(max=Max('price')).values('publisher_id', 'max', 'title') # 查找每個(gè)出版社出版價(jià)格最高的書(shū)籍價(jià)格,這是我之前做的方法,也是正確的可以相較而看# 單表分組,book表以publisher_id分組,統(tǒng)計(jì)每組的最大價(jià)格,注意后面的values()中不要包含book表的字段(如果后面的values中包含了book的字段如'title',那么會(huì)以 'publisher_id'和'title'一起進(jìn)行分組,這樣就亂了)# 這種方法有個(gè)問(wèn)題是不同publisher_id但是同一個(gè)出版社名字的不會(huì)被分到一組ret = models.Book.objects.values('publisher_id').annotate(Max('price')).values('publisher_id','max')# 連表分組,book表和publisher表聯(lián)合,以publisher表的name進(jìn)行分組,統(tǒng)計(jì)每組的最大價(jià)格,正確答案,也符合sql語(yǔ)句的查詢邏輯ret = models.Book.objects.values('publisher__name').annotate(Max('price')).values('publisher_id','max')# 單表分組,連表查詢 ,以publisher表的id進(jìn)行分組,查詢book的最大價(jià)格,同樣也是有不同publisher_id但是同一個(gè)出版社名字的不會(huì)被分到一組的問(wèn)題ret = models.Publisher.objects.annotate(Max('book__price')).values('book__price__max')# 單表分組,連表查詢 ,以publisher表的name進(jìn)行分組,查詢book的最大價(jià)格,不會(huì)有上述問(wèn)題,比較符合人的邏輯ret = models.Publisher.objects.values('name').annotate(Max('book__price')).values('book__price__max')# 查找每個(gè)出版社的名字以及出的書(shū)籍?dāng)?shù)量 # ----這里的Count計(jì)數(shù)的是以publisher分組的book對(duì)象, ret = models.Publisher.objects.annotate(count=Count('book')).values()# 查找書(shū)名是“跟金老板學(xué)開(kāi)車”的書(shū)的出版社出版的其他書(shū)籍的名字和價(jià)格 # ---1,找到出版了“跟金老板學(xué)開(kāi)車”的書(shū)的出版社 models.Publisher.objects.get(book__title='跟金老板學(xué)開(kāi)車') # ---2,篩選出是上述出版社出版的書(shū),使用publisher出版社對(duì)象進(jìn)行篩選 models.Book.objects.filter(publisher=models.Publisher.objects.get(book__title='跟金老板學(xué)開(kāi)車') # ---3.在這些書(shū)里排除 '跟金老板學(xué)開(kāi)車'的書(shū) .exclude(title='跟金老板學(xué)開(kāi)車') ret = models.Book.objects.filter(publisher=models.Publisher.objects.get(book__title='跟金老板學(xué)開(kāi)車')).exclude(title='跟金老板學(xué)開(kāi)車').values('title', 'price')# 法2 # ---1,找到出版了“跟金老板學(xué)開(kāi)車”的書(shū)的出版社 # ---2,通過(guò)外鍵book_set 找到該出版社出版的所有書(shū)籍,此時(shí)的對(duì)象列表已經(jīng)不是出版社,而是書(shū)籍 # ---3,排除 '跟金老板學(xué)開(kāi)車'的書(shū) ret = models.Publisher.objects.get(book__title='跟金老板學(xué)開(kāi)車').book_set.exclude(title='跟金老板學(xué)開(kāi)車').values('title', 'price')# 查找書(shū)名是“跟金老板學(xué)開(kāi)車”的書(shū)的作者們的姓名以及出版的所有書(shū)籍名稱和價(jià)錢# 這樣是有問(wèn)題的,不能這么寫(xiě) ret = models.Author.objects.filter(book__title='跟金老板學(xué)開(kāi)車').values('name', 'book__title', 'book__price').distinct()# 這樣是有問(wèn)題的,不能這么寫(xiě),見(jiàn)下面代碼 ret = models.Book.objects.get(title='跟金老板學(xué)開(kāi)車').author.values('name', 'book__title', 'book__price').distinct()# ---1,找到“跟金老板學(xué)開(kāi)車”的書(shū)籍對(duì)象 # ---2,找到寫(xiě)了'跟金老板學(xué)開(kāi)車'書(shū)籍的所有的作者對(duì)象 # ---3,在所有書(shū)籍中篩選作者在上述作者對(duì)象的書(shū)籍 ret = models.Book.objects.filter(author__in=models.Author.objects.filter(book=models.Book.objects.filter(title='跟金老板學(xué)開(kāi)車'))).values('author__name', 'title', 'price') # 簡(jiǎn)化 ret = models.Book.objects.filter(author__in=models.Author.objects.filter(book__title='跟金老板學(xué)開(kāi)車')).values('author__name', 'title', 'price')?
# 顯示sql語(yǔ)句的命令,在settings中添加下面代碼 LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'console': {'level': 'DEBUG','class': 'logging.StreamHandler',},},'loggers': {'django.db.backends': {'handlers': ['console'],'propagate': True,'level': 'DEBUG',},} } 顯示sql語(yǔ)句的命令,在settings中添加下面代碼?補(bǔ)充
基于雙下劃線的跨表查詢?
Django 還提供了一種直觀而高效的方式在查詢(lookups)中表示關(guān)聯(lián)關(guān)系,它能自動(dòng)確認(rèn) SQL JOIN 聯(lián)系。要做跨關(guān)系查詢,就使用兩個(gè)下劃線來(lái)鏈接模型(model)間關(guān)聯(lián)字段的名稱,直到最終鏈接到你想要的 model 為止。
關(guān)鍵點(diǎn):正向查詢按字段,反向查詢按表明。
?
# 練習(xí)1: 查詢?nèi)嗣癯霭嫔绯霭孢^(guò)的所有書(shū)籍的名字與價(jià)格(一對(duì)多)
# 正向查詢 按字段:publish
queryResult=Book.objects
.filter(publish__name="人民出版社")
.values_list("title","price")
# 反向查詢 按表名:book
queryResult=Publish.objects
.filter(name="人民出版社")
.values_list("book__title","book__price")
?
# 練習(xí)2: 查詢egon出過(guò)的所有書(shū)籍的名字(多對(duì)多)
# 正向查詢 按字段:authors:
queryResult=Book.objects
.filter(authors__name="yuan")
.values_list("title")
# 反向查詢 按表名:book
queryResult=Author.objects
.filter(name="yuan")
.values_list("book__title","book__price")
# 練習(xí)3: 查詢?nèi)嗣癯霭嫔绯霭孢^(guò)的所有書(shū)籍的名字以及作者的姓名
# 正向查詢
queryResult=Book.objects
.filter(publish__name="人民出版社")
.values_list("title","authors__name")
# 反向查詢
queryResult=Publish.objects
.filter(name="人民出版社")
.values_list("book__title","book__authors__age","book__authors__name")
# 練習(xí)4: 手機(jī)號(hào)以151開(kāi)頭的作者出版過(guò)的所有書(shū)籍名稱以及出版社名稱
queryResult=Book.objects
.filter(authors__authorDetail__telephone__regex="151")
.values_list("title","publish__name")
注意:
反向查詢時(shí),如果定義了related_name ,則用related_name替換表名,例如:?publish = ForeignKey(Blog, related_name='bookList'):
# 練習(xí)1:? 查詢?nèi)嗣癯霭嫔绯霭孢^(guò)的所有書(shū)籍的名字與價(jià)格(一對(duì)多)
????# 反向查詢 不再按表名:book,而是related_name:bookList ????queryResult=Publish.objects .filter(name="人民出版社") .values_list("bookList__title","bookList__price")轉(zhuǎn)載于:https://www.cnblogs.com/perfey/p/9648474.html
總結(jié)
- 上一篇: [Flutter] Android沉侵式
- 下一篇: HAProxy详解(二):HAProxy