ORM操作
單表使用ORM對數據庫的增刪改查
ORM與數據庫的對應
類? ?==> 表
對象 ? ==> 記錄
屬性 ==> 字段
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自動將publisher后面加上_id作為字段傳給數據庫,可以使用book_obj.publisher_id找到書籍對象對應的出版社的id,這是直接操作數據庫的# publisher作為ORM中BOOK類的屬性,可以通過book_obj.publisher找到書籍對象對應的出版社對象,這仍然是通過ORM操作數據庫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)帶多對多的表: author_obj = models.Author.objects.create(name='xxxxx')author_obj.books.set([1,3,4])刪除:對象列表.delete()對象.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的數值'(推薦這種寫法,直接操作數據庫)book_obj.save()帶多對多的表 author_obj.name = 'xxx'author_obj.save() author_obj.books.set([1,3,4])查:普通字段: pub_obj.id外鍵字段: book_obj.publisher —— 》 關聯的出版社對象book_obj.publisher_id —— 》 關聯的出版社對象的id多對多字段: author_ob.books —— 》 管理對象 author_ob.books.all() —— 》 作者關聯的所有書籍對象列表?
?
?
常用字段?
AutoField
自增的整形字段,必填參數primary_key=True,則成為數據庫的主鍵。無該字段時,django自動創建。
一個model不能有兩個AutoField字段。
IntegerField
一個整數類型。數值的范圍是?-2147483648 ~ 2147483647。
CharField
字符類型,必須提供max_length參數。max_length表示字符的長度。
DateField
日期類型,日期格式為YYYY-MM-DD,相當于Python中的datetime.date的實例。
參數:
- auto_now:每次修改時修改為當前日期時間。
- auto_now_add:新創建對象時自動添加當前日期時間。
auto_now和auto_now_add和default參數是互斥的,不能同時設置。
DatetimeField
?
復制代碼AutoField(Field)- int自增列,必須填入參數 primary_key=TrueBigAutoField(AutoField)- bigint自增列,必須填入參數 primary_key=True注:當model中如果沒有自增列,則自動會創建一個列名為id的列from django.db import modelsclass UserInfo(models.Model):# 自動創建一個列名為id的且為自增的整數列username = models.CharField(max_length=32)class Group(models.Model):# 自定義自增列nid = models.AutoField(primary_key=True)name = models.CharField(max_length=32)SmallIntegerField(IntegerField):- 小整數 -32768 ~ 32767PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正小整數 0 ~ 32767IntegerField(Field)- 整數列(有符號的) -2147483648 ~ 2147483647PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正整數 0 ~ 2147483647BigIntegerField(IntegerField):- 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807BooleanField(Field)- 布爾值類型NullBooleanField(Field):- 可以為空的布爾值CharField(Field)- 字符類型- 必須提供max_length參數, max_length表示字符長度TextField(Field)- 文本類型EmailField(CharField):- 字符串類型,Django Admin以及ModelForm中提供驗證機制IPAddressField(Field)- 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制GenericIPAddressField(Field)- 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6- 參數:protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"unpack_ipv4, 如果指定為True,則輸入::ffff:192.0.2.1時候,可解析為192.0.2.1,開啟此功能,需要protocol="both"URLField(CharField)- 字符串類型,Django Admin以及ModelForm中提供驗證 URLSlugField(CharField)- 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、連接符(減號)CommaSeparatedIntegerField(CharField)- 字符串類型,格式必須為逗號分割的數字UUIDField(Field)- 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證FilePathField(Field)- 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能- 參數:path, 文件夾路徑match=None, 正則匹配recursive=False, 遞歸下面的文件夾allow_files=True, 允許文件allow_folders=False, 允許文件夾FileField(Field)- 字符串,路徑保存在數據庫,文件上傳到指定目錄- 參數:upload_to = "" 上傳文件的保存路徑storage = None 存儲組件,默認django.core.files.storage.FileSystemStorageImageField(FileField)- 字符串,路徑保存在數據庫,文件上傳到指定目錄- 參數:upload_to = "" 上傳文件的保存路徑storage = None 存儲組件,默認django.core.files.storage.FileSystemStoragewidth_field=None, 上傳圖片的高度保存的數據庫字段名(字符串)height_field=None 上傳圖片的寬度保存的數據庫字段名(字符串)DateTimeField(DateField)- 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]DateField(DateTimeCheckMixin, Field)- 日期格式 YYYY-MM-DDTimeField(DateTimeCheckMixin, Field)- 時間格式 HH:MM[:ss[.uuuuuu]]DurationField(Field)- 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值為datetime.timedelta類型FloatField(Field)- 浮點型DecimalField(Field)- 10進制小數- 參數:max_digits,小數總長度decimal_places,小數位長度BinaryField(Field)- 二進制類型 詳細字段類型?
#自定義一個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):"""限定生成數據庫表的字段類型為char,長度為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 數據庫中字段是否可以為空db_column 數據庫中字段的列名default 數據庫中字段的默認值primary_key 數據庫中字段是否為主鍵db_index 數據庫中字段是否可以建立索引unique 數據庫中字段是否可以建立唯一索引unique_for_date 數據庫中字段【日期】部分是否可以建立唯一索引unique_for_month 數據庫中字段【月】部分是否可以建立唯一索引unique_for_year 數據庫中字段【年】部分是否可以建立唯一索引verbose_name Admin中顯示的字段名稱blank Admin中是否允許用戶輸入為空editable Admin中是否可以編輯help_text Admin中該字段的提示信息choices Admin中顯示選擇框的內容,用不變動的數據放在內存中從而避免跨表操作如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)error_messages 自定義錯誤信息(字典類型),從而定制想要顯示的錯誤信息;字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date如:{'null': "不能為空.", 'invalid': '格式錯誤'}validators 自定義錯誤驗證(列表類型),從而定制想要的驗證規則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': '優先錯信息1','c2': '優先錯信息2','c3': '優先錯信息3',},validators=[RegexValidator(regex='root_\d+', message='錯誤了', code='c1'),RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'),EmailValidator(message='又錯誤了', code='c3'), ])字段參數 字段參數Model Meta參數
app01 下的models.pyclass UserInfo(models.Model):nid = models.AutoField(primary_key=True)username = models.CharField(max_length=32)class Meta:# 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名db_table = "table_name"# admin中顯示的表名稱verbose_name = '個人信息'# verbose_name加sverbose_name_plural = '所有用戶信息'# 聯合索引 index_together = [("pub_date", "deadline"), # 應為兩個存在的字段 ]# 聯合唯一索引unique_together = (("driver", "restaurant"),) # 應為兩個存在的字段
普通索引:僅加速查詢
唯一索引:加速查詢 + 列值唯一(可以有null)
主鍵索引:加速查詢 + 列值唯一 + 表中只有一個(不可以有null)
組合索引:多列值組成一個索引,
? ? ? ? ? ? ? 專門用于組合搜索,其效率大于索引合并
全文索引:對文本的內容進行分詞,進行搜索?
查詢的13條命令?
不必非在app下的models進行ORM操作,可以在項目目錄下新建文件夾,新建py文件進行ORM操作
我們在django中運行項目都是通過manage.py來完成的,下面的代碼設置的一些環境在manage.py中也有,可以直接粘過來
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings") # orm_practice是當前的項目名import djangodjango.setup()from app01 import models# all 獲取所有對象 ——》 QuerySetret = models.Person.objects.all()# get 獲取單獨的對象 ——》 對象# 找不到或者找到多個就報錯ret= models.Person.objects.get(id=1,name='阿旭')# filter 過濾 獲取所有滿足條件的對象 ——》QuerySetret = models.Person.objects.filter(id=1)# exclude 獲取不滿足條件的所有對象ret = models.Person.objects.exclude(id=1)# values ——》QuerySet 元素是字典# 不寫參數 默認所有字段的名字和值# 寫參數 拿到指定字段的名字和值ret = models.Person.objects.all().values('id','name')ret = models.Person.objects.values('id','name')# values_list ——》QuerySet 元素是元組 只有值沒有字段名# 不寫參數 默認所有字段值# 寫參數 拿到指定字段值ret = models.Person.objects.values_list('name','id')# print(ret)# for i in ret :# print(i,type(i))# reverse 對已經排序的QuerySet進行反轉ret = models.Person.objects.all().reverse()# distinct 去重 ——》QuerySet# count 對QuerySet中的元素進行計數ret = models.Person.objects.filter(id=100).count()# first 取QuerySet中的第一個元素ret = models.Person.objects.all().first()# last 取QuerySet中的最后一個元素ret = models.Person.objects.all().last()ret = models.Person.objects.values_list().last()ret = models.Person.objects.filter(id=100).first()# exists 判斷查詢結果是否有值ret = models.Person.objects.filter(id=100).exists()# print(ret)# order_by 按字段進行排序 ——》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()返回是對象 1. get() 2. first() 3. last()返回是布爾值 1. exists()返回是數字 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) #并且的關系ret = models.Person.objects.filter(id__range=[1, 5]) # id范圍在1-5包括1和5ret = models.Person.objects.filter(name__contains='A') # name包含'A'類似于sql語句中的likeret = models.Person.objects.filter(name__icontains='a') # name中包含'A'或'a',不區分大小寫 ret = models.Person.objects.filter(name__istartswith='a') # 以'a'開頭ret = models.Person.objects.filter(name__endswith='x') # 以'x'結尾 ret = models.Person.objects.filter(birth__year='2018') # 篩選年份為'2018'日期的對象ret = models.Person.objects.filter(birth__month='09') # 篩選月份為'09'日期的對象ret = models.Person.objects.filter(name__isnull=True) # 篩選名字不為空的對象print(ret)跨表查詢(連表查詢)中的雙下劃線表示另一個關聯表(外鍵關聯或多對多關聯)中的字段.
如ret= models.Book.objects.filter(publisher__name='沙河出版社')? ??publisher__name表示publisher表中的name字段? ?這個語句的意思是篩選出所有 出版社為沙河出版社出版的書籍
import osif __name__ == '__main__':os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")import djangodjango.setup()from app01 import models# 正向查詢 book ——》 publisher# 基于對象查詢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) # 關聯的出版社對象print(book_obj.publisher.id) # 關聯的出版社對象print(book_obj.publisher.name)# 基于字段查詢ret= models.Book.objects.filter(publisher__name='沙河出版社')ret= models.Book.objects.filter(publisher_id=1)print(ret)# 反向查詢 publisher ——》 book# 基于對象的查詢# 1 —— 》 多 表名小寫_set ——》 管理對象 .all() 出版社關聯的所有書籍對象pub_obj = models.Publisher.objects.first()# 表名小寫_set ,注意是表名小寫_set 而不是子表(多對一中的多)的外鍵名_set ret = pub_obj.book_set.all() print(pub_obj.book_set,type(pub_obj.book_set)) book_set是外鍵反向查詢的管理對象print(ret)class Book(models.Model):title = models.CharField(max_length=32)publisher = models.ForeignKey('Publisher',related_name='books', # 關聯名字# related_query_name='xx', #關聯查詢名字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='跟太亮學開車') 表名#2,指定related_name 不指定related_query_nameret = models.Publisher.objects.filter(books__title='跟太亮學開車') 使用related_name 指定的名字 'books'#3,指定related_name和related_query_nameret = models.Publisher.objects.filter(xx__title='跟太亮學開車') 使用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是多對多管理對象 # 多對多中的 creat() add() remove() clear()# create()# author_obj.books.create(title='戴綠與嫂子的故事',publisher_id=1)# 1. 創建書籍對象(與出版社進行關聯)# 2. 該對象和作者進行關聯# add()book_list = models.Book.objects.filter(id__in=[1,6,8,9])author_obj.books.add(*books_list) # 增加作者對應的書籍 可以寫id 可以寫對象,book_list是對象列表,需要用*打散# set()author_obj.books.set([1,6,8,9]) # 用書籍id設置作者對應的書籍 author_obj.books.set(books)author_obj.books.remove(*books)author_obj.books.clear()# 一對多中的 creat() remove() clear()pub_obj= models.Publisher.objects.first()pub_obj.book_set book_set是反向查詢的管理對象pub_obj.books.create(title='跟老男孩學思想')pub_obj = models.Publisher.objects.get(id=1)# 一對多的管理對象remove不能使用id 使用對象pub_obj.books.remove(models.Book.objects.get(id=5))pub_obj.books.clear() # 清空關聯的書籍聚合和分組
聚合:aggregate(*args,**kwargs)
通過對QuerySet進行計算,返回一個聚合值的字典。aggregate()中每一個參數都指定一個包含在字典中的返回值。即在查詢集上生成聚合。
聚合的結果不包含原來表中的字段,aggregate()是QuerySet 的一個終止子句,只能在最后寫他
分組:annotate(*args,**kwargs):
可以通過計算查詢結果中每一個對象所關聯的對象集合,從而得出總計值(也可以是平均值或總和),即為查詢集的每一項生成聚合。
對分組后的每一組進行查詢計算,然后將結果作為注釋添加到表每行的數據中
簡單看下用法,詳細用法見下面的練習代碼
#查詢alex出的書的總價格 Book.object.filter(authors__name='alex').aggregate(Sum('price')) #查詢各個作者出的書的總價格,這里就涉及到分組了,分組條件是anthors__name Book.object.values('authors__name').annotate(Sum('price')) #查詢各個出版社最便宜的書價是多少 Book.object.values('publisher__name').annotate(Min('price'))F查詢和Q查詢
??
#僅僅靠單一的關鍵字參數查詢已經很難滿足查詢要求。此時Django為我們提供了F查詢和Q查詢 # F 使用查詢條件的值,專門取對象中某列值的操作 models.Tb1.objects.update(num=F('num')+1) # 將num加1后重新賦值給num # Q 構建搜索條件 models.Book.objects.filter(Q(id__lt=3)|Q(id__gt=5)).values() # filter中兩個條件以逗號分隔是and的關系,使用Q查詢可以有或的關系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() # 一個字段的比較不用使用F查詢ret = models.Book.objects.filter(sale__gte=F('kucun')+30).values() # 兩個字段的值進行比較需要使用F查詢 ret = models.Book.objects.filter(~Q(id__lt=3)|Q(id__gt=5)).values() # ~是取反 和!意義一樣for i in ret:print(i)# updata()和save()的區別,updata只修改條件內的表的字段,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)詳細說明
# F 使用查詢條件的值,專門取對象中某列值的操作from django.db.models import Fmodels.Tb1.objects.update(num=F('num')+1)# Q 構建搜索條件from django.db.models import Q# 1 Q對象(django.db.models.Q)可以對關鍵字參數進行封裝,從而更好地應用多個查詢q1 = models.Book.objects.filter(Q(title__startswith='P')).all()print(q1) # [<Book: Python>, <Book: Perl>]# 2、可以組合使用&,|操作符,當一個操作符是用于兩個Q的對象,它產生一個新的Q對象。Q(title__startswith='P') | Q(title__startswith='J')# 3、Q對象可以用~操作符放在前面表示否定,也可允許否定與不否定形式的組合Q(title__startswith='P') | ~Q(pub_date__year=2005)# 4、應用范圍:# 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對象可以與關鍵字參數查詢一起使用,不過一定要把Q對象放在關鍵字參數查詢的前面。# 正確:Book.objects.get(Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),title__startswith='P')# 錯誤:Book.objects.get(question__startswith='P',Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))事務
?通過事務我們可以把兩件或者兩件以上的ORM操作組成一個原子,這幾件事要么都成功,一旦有一個失敗了,那么全部不執行,即使執行過了也要回滾回去
比如,我們操作數據庫進行轉賬操作,A向B轉賬分為兩步,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 # 導入從django事務模塊import datetimewith transaction.atomic():new_publisher = models.Publisher.objects.create(name="火星出版社") # 這條語句單獨是可以成功的models.Book.objects.create(title="橘子物語",publisher_id=100) # 指定一個不存在的出版社id,這條語句會報錯,所以作為整體,事務內所有語句都不會執行except Exception as e:print(str(e))
ORM查詢練習
簡單說明:? ? publisher? ? ?字段? ?id? ? name? ?city
book? ? ? ? ? ? 字段? ?id? ? title? ? publish_date? ? ?price? ? ?memo? ? ? publisher(外鍵關聯了publisher)? ? author(多對多管理對象,關聯了作者)
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# 查找所有書名里包含金老板的書 ret = models.Book.objects.filter(title__contains='金老板')# 查找出版日期是2018年的書 ret = models.Book.objects.filter(publish_date__year=2018)# 查找價格大于10元的書 ret = models.Book.objects.filter(price__gt=10)# 查找memo字段是空的書 # -----字段為空包括空字符串和null , null和空字符串并不是一回事 ret = models.Book.objects.filter(Q(memo='') | Q(memo__isnull=True))# 查找名字以沙河開頭的出版社 # ----distinct去重,有兩個名字相同但是id不同的沙河出版社對象,所以這個去重并不能給對象去重,需要先使用values()取出出版社的名字,這樣變成字典后再對名字進行去重 ret = models.Publisher.objects.filter(name__startswith='沙河').values('name').distinct()# 查找“沙河出版社”出版的所有書籍 # ----連表查詢,使用另一個表的屬性時要使用雙下劃線 ret = models.Book.objects.filter(publisher__name='沙河出版社')# 查找每個出版社出版價格最高的書籍價格 # ----annotate分組聚合,分組后就一定要使用聚合函數,annotate在官方文檔的意思是注釋的意思,給表中每行的數據添加注釋 # ----對annotate前的表進行分組,annotate前有values的話,是以values中的值進行分組,沒有values默認以annotate前表的id進行分組 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') # 查找每個出版社出版價格最高的書籍價格,這是我之前做的方法,也是正確的可以相較而看# 單表分組,book表以publisher_id分組,統計每組的最大價格,注意后面的values()中不要包含book表的字段(如果后面的values中包含了book的字段如'title',那么會以 'publisher_id'和'title'一起進行分組,這樣就亂了)# 這種方法有個問題是不同publisher_id但是同一個出版社名字的不會被分到一組ret = models.Book.objects.values('publisher_id').annotate(Max('price')).values('publisher_id','max')# 連表分組,book表和publisher表聯合,以publisher表的name進行分組,統計每組的最大價格,正確答案,也符合sql語句的查詢邏輯ret = models.Book.objects.values('publisher__name').annotate(Max('price')).values('publisher_id','max')# 單表分組,連表查詢 ,以publisher表的id進行分組,查詢book的最大價格,同樣也是有不同publisher_id但是同一個出版社名字的不會被分到一組的問題ret = models.Publisher.objects.annotate(Max('book__price')).values('book__price__max')# 單表分組,連表查詢 ,以publisher表的name進行分組,查詢book的最大價格,不會有上述問題,比較符合人的邏輯ret = models.Publisher.objects.values('name').annotate(Max('book__price')).values('book__price__max')# 查找每個出版社的名字以及出的書籍數量 # ----這里的Count計數的是以publisher分組的book對象, ret = models.Publisher.objects.annotate(count=Count('book')).values()# 查找書名是“跟金老板學開車”的書的出版社出版的其他書籍的名字和價格 # ---1,找到出版了“跟金老板學開車”的書的出版社 models.Publisher.objects.get(book__title='跟金老板學開車') # ---2,篩選出是上述出版社出版的書,使用publisher出版社對象進行篩選 models.Book.objects.filter(publisher=models.Publisher.objects.get(book__title='跟金老板學開車') # ---3.在這些書里排除 '跟金老板學開車'的書 .exclude(title='跟金老板學開車') ret = models.Book.objects.filter(publisher=models.Publisher.objects.get(book__title='跟金老板學開車')).exclude(title='跟金老板學開車').values('title', 'price')# 法2 # ---1,找到出版了“跟金老板學開車”的書的出版社 # ---2,通過外鍵book_set 找到該出版社出版的所有書籍,此時的對象列表已經不是出版社,而是書籍 # ---3,排除 '跟金老板學開車'的書 ret = models.Publisher.objects.get(book__title='跟金老板學開車').book_set.exclude(title='跟金老板學開車').values('title', 'price')# 查找書名是“跟金老板學開車”的書的作者們的姓名以及出版的所有書籍名稱和價錢# 這樣是有問題的,不能這么寫 ret = models.Author.objects.filter(book__title='跟金老板學開車').values('name', 'book__title', 'book__price').distinct()# 這樣是有問題的,不能這么寫,見下面代碼 ret = models.Book.objects.get(title='跟金老板學開車').author.values('name', 'book__title', 'book__price').distinct()# ---1,找到“跟金老板學開車”的書籍對象 # ---2,找到寫了'跟金老板學開車'書籍的所有的作者對象 # ---3,在所有書籍中篩選作者在上述作者對象的書籍 ret = models.Book.objects.filter(author__in=models.Author.objects.filter(book=models.Book.objects.filter(title='跟金老板學開車'))).values('author__name', 'title', 'price') # 簡化 ret = models.Book.objects.filter(author__in=models.Author.objects.filter(book__title='跟金老板學開車')).values('author__name', 'title', 'price')?
# 顯示sql語句的命令,在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語句的命令,在settings中添加下面代碼?補充
基于雙下劃線的跨表查詢?
Django 還提供了一種直觀而高效的方式在查詢(lookups)中表示關聯關系,它能自動確認 SQL JOIN 聯系。要做跨關系查詢,就使用兩個下劃線來鏈接模型(model)間關聯字段的名稱,直到最終鏈接到你想要的 model 為止。
關鍵點:正向查詢按字段,反向查詢按表明。
?
# 練習1: 查詢人民出版社出版過的所有書籍的名字與價格(一對多)
# 正向查詢 按字段:publish
queryResult=Book.objects
.filter(publish__name="人民出版社")
.values_list("title","price")
# 反向查詢 按表名:book
queryResult=Publish.objects
.filter(name="人民出版社")
.values_list("book__title","book__price")
?
# 練習2: 查詢egon出過的所有書籍的名字(多對多)
# 正向查詢 按字段:authors:
queryResult=Book.objects
.filter(authors__name="yuan")
.values_list("title")
# 反向查詢 按表名:book
queryResult=Author.objects
.filter(name="yuan")
.values_list("book__title","book__price")
# 練習3: 查詢人民出版社出版過的所有書籍的名字以及作者的姓名
# 正向查詢
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")
# 練習4: 手機號以151開頭的作者出版過的所有書籍名稱以及出版社名稱
queryResult=Book.objects
.filter(authors__authorDetail__telephone__regex="151")
.values_list("title","publish__name")
注意:
反向查詢時,如果定義了related_name ,則用related_name替換表名,例如:?publish = ForeignKey(Blog, related_name='bookList'):
# 練習1:? 查詢人民出版社出版過的所有書籍的名字與價格(一對多)
????# 反向查詢 不再按表名:book,而是related_name:bookList ????queryResult=Publish.objects .filter(name="人民出版社") .values_list("bookList__title","bookList__price")轉載于:https://www.cnblogs.com/perfey/p/9648474.html
總結
- 上一篇: [Flutter] Android沉侵式
- 下一篇: HAProxy详解(二):HAProxy