建立名爲book的APP,在book下的models.py中建立模型:php
from django.db import models # Create your models here. class Book(models.Model): id = models.AutoField(primary_key = True) title=models.CharField(max_length=32) state=models.BooleanField() pub_date=models.DateField() price=models.DecimalField(max_digits=8,decimal_places=2) publish=models.CharField(max_length=32)
若要想將模型轉爲MySQL數據庫中的表,須要在settings中配置。python
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'bms', # 要鏈接的數據庫,鏈接前須要建立好 'USER':'root', # 鏈接數據庫的用戶名 'PASSWORD':'', # 鏈接數據庫的密碼 'HOST':'127.0.0.1', # 鏈接主機,默認本級 'PORT':3306 # 端口 默認3306 } }
注意:Name名字即爲數據庫的名字,在MySQL鏈接前該數據庫必須已經建立,而上面的SQLite數據庫下的db.sqlite3則是項目自動建立USER和PASSWORD分佈式數據庫的用戶名和密碼。設置完後,再啓動咱們的Django項目前,咱們須要激活咱們的MySQL。而後,啓動項目,會報錯:no module named MySQLdb 。這是由於django默認你導入的驅動是MySQLdb,但是MySQLdb對於py3有很大問題,因此咱們須要的驅動是PyMySQL,因此咱們只須要找到項目文件下的init,在裏面寫入:mysql
import pymysql pymysql.install_as_MySQLdb()
最後經過兩條數據庫遷移命令便可在指定數據庫中建立表:git
python manage.py makemigrations python manage.py migrate
注意:確保配置文件中的INSTALLED_APPS中寫入咱們建立的APP名稱web
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', "book" ]
注意:若是想打印ORM轉換過程當中的SQL,須要在settings中進行以下配置:ajax
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
APP/urls.pysql
from user9_one import views from django.urls import path urlpatterns = [ path('book/', views.book), ]
ADMIN/urls.py數據庫
from django.contrib import admin from django.urls import path from django.conf.urls import url, include urlpatterns = [ path('admin/', admin.site.urls), path('user7_auth/', include('user7_auth.urls')), path('user8_book/', include('user8_book.urls')), path('user9_one/', include('user9_one.urls')), path('user10_many/', include('user10_many.urls')), path('user11_ajax/', include('user11_ajax.urls')), ]
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') user=models.User.objects.create(name=name,password=pwd,address=addr)
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') user=models.User(name=name,password=pwd,address=addr) user.save()
from django.shortcuts import render,HttpResponse # Create your views here. from user9_one.models import Book def book(requset): # create 方法的返回值book_obj就是插入book表中的python1這本書的記錄 title = 'python1' state = True price = 100 publish = '機械出版社' pub_date = '2019-3-3' book_obj = Book.objects.create(title=title, state=state, price=price, publish=publish, pub_date=pub_date) title = 'python2' state = True price = 200 publish = '機械出版社' pub_date = '2019-2-3' book_obj2 = Book(title=title, state=state, price=price, publish=publish, pub_date=pub_date) book_obj2.save() return HttpResponse("create ok")
注意:update方法對於任何結果集(QuerySet)有效,能夠同時更新多條記錄,使用update()方法會返回一個整數數值,表示受影響的記錄條數。django
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') models.User.objects.filter(id=id).update(name=name,password=pwd,address=addr)
# first()是返回第一條記錄 user = models.User.objects.filter(name='python').first() user.pwd = '******' user.save()
def book(requset): id = 1 title = 'python3' state = True price = 400 publish = '機械出版社' pub_date = '2019-9-13' book_obj = Book.objects.filter(id=id).update(title=title, state=state, price=price, publish=publish, pub_date=pub_date) id = 2 book_obj2 = Book.objects.filter(id=id).first() book_obj2.title = 'python4' book_obj2.state = True book_obj2.price = 400 book_obj2.publish = '機械出版社' book_obj2.pub_date = '2019-6-13' book_obj2.save() return HttpResponse("update ok")
刪除方法就是delete()。它運行時當即刪除對象而不返回任何值。例如:緩存
model_obj.delete()
你也能夠一次性刪除多個對象,每一個QuerySet都有一個delete()方法,它一次性刪除QuerySet中全部對象。
要注意的是:delete()方法是QuerySet上的方法,可是並不適用於Manager自己。這是一種保護機制,是爲了不意外地調用Entry.objects.delete()方法致使全部的記錄被誤刪除。若是你確認要刪除全部的對象,那麼你必須顯式的調用:
model.User.objects.all().delete()
若是不想級聯刪除,能夠設置爲:
pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL, blank=True, null=True)
id = request.GET.get('id') ret1 = models.User.objects.filter(id=id).delete() ret = models.Book.objects.filter(name='james').first() ret.delete()
例如,下面的代碼將刪除pub_date是2019年的Entry對象:
Entry.objects.filter(pub_date__year=2019).delete()
在django刪除對象時,會模仿SQL約束ON DELETE CASCADE的行爲,換句話說,刪除一個對象時也會刪除與它相關聯的外鍵對象。例如:
b = Blog.objects.get(pk=1) # This will delete the Blog and all of its Entry objects. b.delete()
def book(requset): id = 7 ret = Book.objects.filter(id=id).delete() Book.objects.all().delete() return HttpResponse("delete ok")
以前:
以後:
查詢操做是Django的ORM框架中最重要的內容之一,下面是咱們經常使用到與查詢相關的API
注意:必定要區分出object 和 QuerySet 的區別 !!!
QuerySet是查詢集,就是傳到服務器上的url裏面的內容,Django會對查詢返回的結果集QuerySet進行緩存,這是是爲了提升查詢效率。也就是說,在建立一個QuerySet對象的時候,Django並不會當即向數據庫發出查詢命令,只有在你須要用到這個QuerySet的時候纔去數據庫查詢。
Object是django實現的MVC框架中的數據層(model)M,django中的模型類都有一個object對象,他是django中定義的QuerySet類型的對象,它包含了模型對象的實例。
簡單來講,object是單個對象,QuerySet是許多對象。
filter(字段名__gt='') ---- 大於 filter(字段名__lt='') ---- 小於 filter(字段名__lte='') ---- 小於等於 filter(字段名__gte='') ---- 大於等於 filter(字段名__in='') ---- 字段存在列表中 filter(字段名__range='') ---- 字段數據在範圍內(between and) filter(字段名__contains='') ---- 字段數據包含內容 模糊查詢 like % % filter(字段名__icontains='') ---- 字段數據包含內容,而且忽略大小寫 模糊查詢 like % % filter(字段名__startswith='') ---- 字段數據之內容開頭 filter(字段名__endswith='') ---- 字段數據之內容結尾 filter(字段名__year='') ---- 查詢字段內容以指定年份查詢 filter(字段名__month='') ---- 查詢字段內容以指定月份查詢 filter(字段名__day='') ---- 查詢字段內容以指定日期查詢
示例:
def book(requset): # filter(字段名__gt='') ---- 大於 # 查詢價格大於200 的書 ret1 = Book.objects.filter(price__gt='200') # filter(字段名__lt='') ---- 小於 # 查詢價格小於200 的書 ret2 = Book.objects.filter(price__lt='200') # filter(字段名__lte='') ---- 小於等於 ret3 = Book.objects.filter(price__lte='200') # filter(字段名__gte='') ---- 大於等於 ret4 = Book.objects.filter(price__gte='200') # filter(字段名__in='') ---- 字段存在列表中 ret5 = Book.objects.filter(price__in=['2001', '1000', '1001']) # filter(字段名__range='') ---- 字段數據在範圍內(between and) ret6 = Book.objects.filter(price__range=[500, 1500]) # filter(字段名__contains='') ---- 字段數據包含內容 模糊查詢 like % % # 查詢名字有'%python%'的書 ret7 = Book.objects.filter(title__contains='python') # filter(字段名__icontains='') ---- 字段數據包含內容,而且忽略大小寫 模糊查詢 like % % # 查詢名字帶p的書,忽略大小寫 ret8 = Book.objects.filter(title__icontains='P') # filter(字段名__startswith='') ---- 字段數據之內容開頭 ret9 = Book.objects.filter(title__startswith='p') # filter(字段名__endswith='') ---- 字段數據之內容結尾 ret10 = Book.objects.filter(title__endswith='5') # filter(字段名__year='') ---- 查詢字段內容以指定年份查詢 ret11 = Book.objects.filter(pub_date__year='2019') # filter(字段名__month='') ---- 查詢字段內容以指定月份查詢 ret12 = Book.objects.filter(pub_date__month='4') # filter(字段名__day='') ---- 查詢字段內容以指定日期查詢 ret13 = Book.objects.filter(pub_date__day='3') print(ret1) print(ret2) print(ret3) print(ret4) print(ret5) print(ret6) print(ret7) print(ret8) print(ret9) print(ret10) print(ret11) print(ret12) print(ret13) return HttpResponse("select ok")
結果:
<QuerySet [<Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]> <QuerySet [<Book: Book object (9)>]> <QuerySet [<Book: Book object (9)>, <Book: Book object (10)>]> <QuerySet [<Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]> <QuerySet [<Book: Book object (11)>, <Book: Book object (13)>, <Book: Book object (14)>]> <QuerySet [<Book: Book object (11)>, <Book: Book object (13)>, <Book: Book object (15)>]> <QuerySet [<Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]> <QuerySet [<Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]> <QuerySet [<Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]> <QuerySet [<Book: Book object (13)>]> <QuerySet [<Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]> <QuerySet [<Book: Book object (12)>]> <QuerySet [<Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]>
首先給數據庫裏面添加一些數據,添加後,數據以下:
def book(requset): # 查詢機械出版社出版的書,返回單個對象 res = Book.objects.filter(publish="機械出版社").first() print(res) # Book object(9) print(type(res)) # <class 'user9_one.models.Book'> # 支持類列表的查詢方式 res1 = Book.objects.filter(publish="機械出版社")[1] print(res1) #Book object (10) # filter內能夠傳多個參數,用逗號分隔,他們是and的關係,返回QuerySet # 若是你在查詢裏面,使用字符串,致使精度不許確,則會報錯,沒法查詢 res2 = Book.objects.filter(publish='機械出版社', price='100') print(res2) #<QuerySet [<Book: Book object (9)>]> return HttpResponse("select ok")
多表關聯是模型層的重要功能之一,Django提供了一套基於關聯字段獨特的解決方案。那就是用OneToOneField,ForeignKey,ManyToMany。
一對一:子表從母表中選出一條數據一一對應,母表中選出來一條就少一條,子表不能夠再選擇母表中已被選擇的那條數據。
一對多:子表從母表中選出一條數據一一對應,但母表的這條數據還能夠被其餘子表數據選擇。
多對多:好比有多個孩子,多種顏色,每一個孩子能夠喜歡多種顏色,一種顏色能夠被多個孩子喜歡,對於雙向均是能夠有多個選擇。
一對一(OneToOneField):通常用於某張表的補充,好比用戶基本信息是一張表,但並不是每一個用戶都須要有登陸的權限,不須要記錄用戶名和密碼,此時,合理的作法就是新建一張記錄登陸信息的表,與用戶信息進行一對一的關聯,能夠方便的從子表查詢母表信息或反向查詢
外鍵(ForeignKey):有不少的應用場景,好比每一個員工歸屬於一個部門,那麼就可讓員工表的部門字段與部門表進行一對多關聯,能夠查詢到一個員工歸屬於哪一個部門,也能夠反向查詢某一部門有哪些員工
多對多(ManyToMany):若有不少公司,一臺服務器可能會有不少種用途,歸屬於多個產品線中,那麼服務器與產品線之間就能夠作成多對,多對多在A表添加ManyToMany字段或者從B表中添加,效果同樣。
ForeignKey 字段接受一個Model類做爲參數,類型與被參照的字段徹底相同:
blog = models.ForeignKey(Blog)
關聯到的關聯對象的字段名稱。默認的,Django使用關聯對象的主鍵。
blog = models.ForeignKey(Blog, to_field = Blog.name)
Django Model的 Foreign 字段的主要功能是維護一個一對多的關係,以進行關聯查詢。只有在db_constraint = True 時Django model 纔會在數據庫上創建外鍵約束,在該值爲False時不創建約束。
默認 db_constraint = True
這個名稱用於讓關聯的對象反查到源對象。
若是你不想讓DJango建立一個反向關聯,請設置related_name 爲 ‘+’ 或者 以‘+’結尾。
ForeignKey.related_query_name以ForeignKey.related_name做爲默認值。
Django會自動建立一個表來管理多對多關係,若要手動指定關聯表則須要使用through關鍵字參數。
上面示例中Membership有兩個外鍵指向Person(person 和 inviter),這使得關聯關係含混不清並讓Django不知道使用哪個,在這種狀況下,必須使用through_fields明確指定Django應該使用哪些外鍵。through_fields 接收一個二元組('field1' , 'field2'),其中field1爲指向定義ManyToManyField字段的模型的外鍵名稱(本例中爲group),field2爲指向目標模型的外鍵的名稱(本例中爲person)。
默認狀況下,關聯表的名稱使用多對多字段的名稱和包含這張表的模型的名稱以及Hash值生成,如:memberShip_person_3c1f5,若想要手動指定表的名稱,可使用db_table 關鍵字參數指定。
對於最新版本的Django2.0 在使用一對一(OneToOneField)和外鍵(ForeignKey)時,須要加上on_delete 參數,否則就會報錯,
若是剛使用django2.0 的是,遇到報錯以下,則是沒有給外鍵添加on_delete參數:
TypeError: __init__() missing 1 required positional argument: 'on_delete'
from django.conf import settings from django.db import models class MySpecialUser(models.Model): user = models.OneToOneField(settings.AUTH_PASSWORD_VALIDATORS, on_delete=models.CASCADE,) supervisor = models.OneToOneField(settings.AUTH_PASSWORD_VALIDATORS, on_delete=models.CASCADE, related_name='supervisor_of',)
from django.db import models class AbstractCar(models.Model): manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE) class Meta: abstract = True
on_delete=None, # 刪除關聯表中的數據時,當前表與其關聯的field的行爲 on_delete=models.CASCADE, # 刪除關聯數據,與之關聯也刪除 on_delete=models.DO_NOTHING, # 刪除關聯數據,什麼也不作 on_delete=models.PROTECT, # 刪除關聯數據,引起錯誤ProtectedError # models.ForeignKey('關聯表', on_delete=models.SET_NULL, blank=True, null=True) on_delete=models.SET_NULL, # 刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空,一對一同理) # models.ForeignKey('關聯表', on_delete=models.SET_DEFAULT, default='默認值') on_delete=models.SET_DEFAULT, # 刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值,一對一同理) on_delete=models.SET, # 刪除關聯數據, a. 與之關聯的值設置爲指定值,設置:models.SET(值) b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象)
多對多不須要on_delete。
做者模型 : 姓名 年齡 做者詳細模型 : 生日 手機號碼 家庭住址等等 出版商模型 : 出版商名稱 所在城市 email 書籍模型 : 書名 出版日期 (做者模型 和 做者詳細模型 是一對一關係 one-to -one) (一本書可能會有多個做者, 一個做者也能夠寫多本書) (做者 和 書籍 是多對多的關係 many -to -many) (一本書只應該由一個出版商出版, 出版商和書籍是一對多關聯關係 one - to - many)
from django.db import models # Create your models here. class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() # 與AuthorDetail創建一對一的關係 authorDetail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE) class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday = models.DateField() telephone = models.BigIntegerField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) publishDate = models.DateField() # max_digits=None, 總長度 decimal_places=None,小數位長度 price = models.DecimalField(max_digits=5, decimal_places=2) # 與publish創建一對多的關係,外鍵字段創建在多的一方 publish = models.ForeignKey(to='Publish', to_field='nid',on_delete=models.CASCADE) # 與Author 創建多對多的關係,ManyToManyField能夠建在兩個模型中的任意一個,自動建立第三張表 authors = models.ManyToManyField(to='Author',)
操做前先簡單的錄入一些數據
def insert_data(request): publish_obj = Publish.objects.get(nid=1) book_obj = Book.objects.create(title='秦腔', publishDate='2016-8-28', price=1005, publish=publish_obj) book_obj2 = Book.objects.create(title="追風箏的人", publishDate='2017-4-9', price=124, publish_id=2) return HttpResponse("insert data ok")
def insert_data(request): # 生成當前的書籍對象 book_obj = Book.objects.create(title='秦腔', publishDate='2016-8-28', price=1005, publish_id=1) # 爲書籍綁定的作做者對象 author_james = Author.objects.filter(name='james').first() # 在Author表中主鍵爲1的記錄 author_durant = Author.objects.filter(name='durant').first() # 在Author表中主鍵爲2的記錄 # 綁定多對多關係,即向關係表book_authors中添加數據 book_obj.authors.add(author_james, author_durant) # 將某些特定的model對象添加到被關聯對象集合中 # book_obj.authors.add(*[]) return HttpResponse("insert data ok")
# 將某個特定的對象從被關聯對象集合中去除。 book_obj.authors.remove() book_obj.authors.remove(*[]) #清空被關聯對象集合 book_obj.authors.clear() #先清空再設置 book_obj.authors.set()
建立一個新的對象,保存對象,並將它添加到關聯對象集之中。返回新建立的對象: >>> b = Blog.objects.get(id=1) >>> e = b.entry_set.create( ... headline='Hello', ... body_text='Hi', ... pub_date=datetime.date(2005, 1, 1) ... ) # No need to call e.save() at this point -- it's already been saved. 這徹底等價於(不過更加簡潔於): >>> b = Blog.objects.get(id=1) >>> e = Entry( ... blog=b, ... headline='Hello', ... body_text='Hi', ... pub_date=datetime.date(2005, 1, 1) ... ) >>> e.save(force_insert=True) 要注意咱們並不須要指定模型中用於定義關係的關鍵詞參數。在上面的例子中,咱們並無 傳入blog參數給create()。Django會明白新的 Entry對象blog 應該添加到b中。
從關聯對象集中移除執行的模型對象: >>> b = Blog.objects.get(id=1) >>> e = Entry.objects.get(id=234) >>> b.entry_set.remove(e) # Disassociates Entry e from Blog b. 對於ForeignKey對象,這個方法僅在null=True時存在。
從關聯對象集中移除一切對象。 >>> b = Blog.objects.get(id=1) >>> b.entry_set.clear() 注意這樣不會刪除對象 —— 只會刪除他們之間的關聯。 就像 remove() 方法同樣,clear()只能在 null=True的ForeignKey上被調用。
先清空,再設置,編輯書籍時便可用到
注意:對於全部類型的關聯字段,add() ,create(),remove(),clear(),set() 都會立刻更新數據庫。換句話說,在關聯的任何一端,都不須要再調用save()方法。
直接賦值:經過賦值一個新的可跌打的對象,關聯對象集能夠被總體替換掉
>>> new_list = [obj1, obj2, obj3] >>> e.related_set = new_list
若是外鍵關係知足 null =True,關聯管理器會在添加new_list 中的內容以前,首先調用clear()方法來解除關聯集中一切已存在對象的關聯。不然 , new_list中的對象會在已存在的關聯的基礎上被添加。
#一對多(ForeignKey): # 方式一: 因爲綁定一對多的字段,好比publish,存到數據庫中的字段名叫publish_id # 因此咱們能夠直接給這個 # 字段設定對應值: Book.objects.create(title='php', publisher_id=2, #這裏的2是指爲該book對象綁定了Publisher表中id=2的行對象 publication_date='2017-7-7', price=99) #方式二: # <1> 先獲取要綁定的Publisher對象: pub_obj=Publisher(name='河大出版社',address='保定',city='保定', state_province='河北',country='China',website='http://www.hbu.com') OR pub_obj=Publisher.objects.get(id=1) # <2>將 publisher_id=2 改成 publisher=pub_obj #多對多(ManyToManyField()): author1=Author.objects.get(id=1) author2=Author.objects.filter(name='alvin')[0] book=Book.objects.get(id=1) book.authors.add(author1,author2) #等同於: book.authors.add(*[author1,author2]) book.authors.remove(*[author1,author2]) #------------------- book=models.Book.objects.filter(id__gt=1) authors=models.Author.objects.filter(id=1)[0] authors.book_set.add(*book) authors.book_set.remove(*book) #------------------- book.authors.add(1) book.authors.remove(1) authors.book_set.add(1) authors.book_set.remove(1) #注意: 若是第三張表是經過models.ManyToManyField()自動建立的,那麼綁定關係只有上面一種方式 # 若是第三張表是本身建立的: class Book2Author(models.Model): author=models.ForeignKey("Author") Book= models.ForeignKey("Book") # 那麼就還有一種方式: author_obj=models.Author.objects.filter(id=2)[0] book_obj =models.Book.objects.filter(id=3)[0] s=models.Book2Author.objects.create(author_id=1,Book_id=2) s.save() s=models.Book2Author(author=author_obj,Book_id=1) s.save()
#--------------------對象形式的查找-------------------------- # 正向查找 ret1=models.Book.objects.first() print(ret1.title) print(ret1.price) print(ret1.publisher) print(ret1.publisher.name) #由於一對多的關係因此ret1.publisher是一個對象, 而不是一個queryset集合 # 反向查找 ret2=models.Publish.objects.last() print(ret2.name) print(ret2.city) #如何拿到與它綁定的Book對象呢? print(ret2.book_set.all()) #ret2.book_set是一個queryset集合 #---------------了不得的雙下劃線(__)之單表條件查詢---------------- # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 # # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於十一、2二、33的數據 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # # models.Tb1.objects.filter(name__contains="ven") # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 # # models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and # # startswith,istartswith, endswith, iendswith, #----------------了不得的雙下劃線(__)之多表條件關聯查詢--------------- # 正向查找(條件) # ret3=models.Book.objects.filter(title='Python').values('id') # print(ret3)#[{'id': 1}] #正向查找(條件)之一對多 ret4=models.Book.objects.filter(title='Python').values('publisher__city') print(ret4) #[{'publisher__city': '北京'}] #正向查找(條件)之多對多 ret5=models.Book.objects.filter(title='Python').values('author__name') print(ret5) ret6=models.Book.objects.filter(author__name="alex").values('title') print(ret6) #注意 #正向查找的publisher__city或者author__name中的publisher,author是book表中綁定的字段 #一對多和多對多在這裏用法沒區別 # 反向查找(條件) #反向查找之一對多: ret8=models.Publisher.objects.filter(book__title='Python').values('name') print(ret8)#[{'name': '人大出版社'}] 注意,book__title中的book就是Publisher的關聯表名 ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors') print(ret9)#[{'book__authors': 1}, {'book__authors': 2}] #反向查找之多對多: ret10=models.Author.objects.filter(book__title='Python').values('name') print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}] #注意 #正向查找的book__title中的book是表名Book #一對多和多對多在這裏用法沒區別
注意:條件查詢即與對象查詢對應,是指在filter,values等方法中經過__來明確查詢條件
「關聯管理器」 是在一對多或者多對多的關聯上下文中使用的管理器。他存在於下面兩種狀況:ForeignKey關係的「另外一邊」。像這樣:
# models.py from django.db import models class Reporter(models.Model): # ... pass class Article(models.Model): reporter = models.ForeignKey(Reporter)
在上面的例子中,管理器reporter.article_set擁有下面的方法。
MangToManyField關係的兩邊:
class Manager1(models.Model): # ... pass class Manager2(models.Model): manager1 = models.ManyToManyField(Manager1)
查詢操做是Django的ORM框架中最重要的內容之一,下面是咱們經常使用到與查詢相關的API。
注意:必定要區分出object 和QuerySet 的區別
附加SQL查詢extra()
#擴展查詢,有時候DJANGO的查詢API不能方便的設置查詢條件,提供了另外的擴展查詢方法extra: #extra(select=None, where=None, params=None, tables=None,order_by=None, select_params=None (1) Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"}) (2) Blog.objects.extra( select=SortedDict([('a', '%s'), ('b', '%s')]), select_params=('one', 'two')) (3) q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"}) q = q.extra(order_by = ['-is_recent']) (4) Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
正向查詢(按字段:authorDetail)
def select_data(request): # 查詢做者名爲james的電話 james = Author.objects.filter(name='james').first() print(james) print(james.authorDetail.telephone) return HttpResponse("select data ok")
反向查詢(按表名:author)
def select_data(request): # 查詢住址在chengdu的做者姓名 authorDetail_list = AuthorDetail.objects.filter(addr='chengdu') for obj in authorDetail_list: print(obj.author.name) return HttpResponse("select data ok")
正向查詢(按字段:publish)
def select_data(request): # 查詢主鍵爲1的書籍的出版社所在的城市 book_obj = Book.objects.filter(nid=1).first() # book_obj.publish 是主鍵爲1 的書籍對象關聯的出版社對象 print(book_obj.publish.city) return HttpResponse("select data ok")
反向查詢(按表名:book_set)
def select_data(request): publish = Publish.objects.get(name="機械出版社") # 與機械出版社 關聯的全部書籍對象集合 res1 = publish.book_set.all() print(res1) book_list = publish.book_set.all() for book_obj in book_list: print(book_obj.title) return HttpResponse("select data ok")
正向查詢(按字段:author)
def select_data(request): # 查找平凡的世界全部做者的名字以及手機號碼 book_obj = Book.objects.filter(title="秦腔").first() print(book_obj) authors = book_obj.authors.all() print(authors) for author_obj in authors: print(author_obj.name, author_obj.authorDetail.telephone) return HttpResponse("select data ok")
反向查詢(按表名:book_set)
def select_data(request): # 查找james出過的全部書籍的名字 author_obj = Author.objects.get(name='james') print(author_obj) # 與james做者相關的全部書籍 book_list = author_obj.book_set.all() print(book_list) for book_obj in book_list: print(book_obj.title) return HttpResponse("select data ok")
你能夠經過在ForeignKey()和ManyToManyField的定義中設置related_name的值來覆寫FOO_set的名稱。例如,若是Article model中作一下更改:
publish = ForeignKey(Book, related_name='bookList')
那麼接下來,咱們就會看到這樣:
def select_data(request): # 查找人們出版社出版過的全部書籍 publish = Publish.objects.get(name='機械出版社') print(publish) # 與機械出版社關聯的全部書籍對象集合 book_list = publish.bookList.all() print(book_list) return HttpResponse("select data ok")
Django還提供了一種直觀而高效的方法在查詢(lookups)中表示關聯關係,它能自動確認SQL JOIN 聯繫。要作跨關係查詢,就使用兩個下劃線來連接模型(model)間關聯字段的名稱,直到最終連接到你想要的model爲止。
關鍵點:正向查詢按字段,反向查詢按表名
5.1 一對多查詢
def select_data(request): # 查詢機械出版社 出版過的全部書籍的名字與價錢(一對多) # 正向查詢 按字段publish queryResult1 = Book.objects.filter(publish_id=1).values_list('publish__book', 'publish__city') print(queryResult1) # 反向查詢 按表名:book queryResult2 =Publish.objects.filter(nid=2).values_list("book__title", 'book__price') print(queryResult2) return HttpResponse("select data ok")
查詢結果:
<QuerySet [(1, 'xian'), (3, 'xian'), (4, 'xian'), (5, 'xian'), (6, 'xian'), (1, 'xian'), (3, 'xian'), (4, 'xian'), (5, 'xian'), (6, 'xian'), (1, 'xian'), (3, 'xian'), (4, 'xian'), (5, 'xian'), (6, 'xian'), (1, 'xian'), (3, 'xian'), (4, 'xian'), (5, 'xian'), (6, 'xian'), ' ...(remaining elements truncated)...']> <QuerySet [('追風箏的人', Decimal('124.00'))]>
5.2 多對多查詢
def select_data(request): # 查詢james出版過的全部書籍的名字 (多對多) # 正向查詢,按照字段:authors queryResult1 = Book.objects.filter(authors=1).values_list("authors__name",'authors__age','publish__name') print(queryResult1) # 反向查詢 按照表名book queryResult2 = Author.objects.filter(name='durant').values_list("book__authors__name",'age','book__publish__name') print(queryResult2) return HttpResponse("select data ok")
結果展現:
<QuerySet [('james', 34, '機械出版社'), ('james', 34, '機械出版社')]> <QuerySet [('james', 30, '機械出版社'), ('james', 30, '機械出版社'), ('durant', 30, '機械出版社'), ('durant', 30, '機械出版社')]>
5.3 一對一查詢
# 查詢james的手機號 # 正向查詢 ret=Author.objects.filter(name="james").values("authordetail__telephone") # 反向查詢 ret=AuthorDetail.objects.filter(author__name="james").values("telephone")
5.4 混合使用
def select_data(request): # 查詢機械出版社 出版過的全部書籍的名字與做者名字 # 正向查詢 按照字段 authors queryResult1 = Book.objects.filter(publish_id=1).values_list('title', 'authors__name') print(queryResult1) # 反向查詢 按表名:book queryResult2 =Publish.objects.filter(nid=2).values_list("book__title", 'book__price') print(queryResult2) # 查詢手機是以123開頭的做者 出版過的全部書籍名稱以及出版社名稱 queryResult3 = Book.objects.filter(authors__authorDetail__telephone__regex='123').values_list('title', 'publish__name') print(queryResult3) return HttpResponse("select data ok")
結果展現:
<QuerySet [('秦腔', 'james'), ('秦腔', 'james'), ('秦腔', 'durant'), ('秦腔', 'durant'), ('平凡的世界', None), ('平凡的世界2', None), ('秦腔', None)]> <QuerySet [('追風箏的人', Decimal('124.00'))]> <QuerySet [('秦腔', '機械出版社'), ('秦腔', '機械出版社')]>
注意:反向查詢時,若是定義了related_name,則用related_name替換表名,例如:
publish = ForeignKey(Blog, related_name='bookList')
def select_data(request): # 查詢機械出版社 出版過的全部書籍的名字與價格 # 正向查詢 按照字段 authors queryResult1 = Book.objects.filter(publish_id=1).values_list('title', 'price') print(queryResult1) # 反向查詢 再也不按照表名book,而是related_name:bookList queryResult2 = Publish.objects.filter(name='機械出版社').values_list("book__title","book__price") print(queryResult2) return HttpResponse("select data ok")
結果展現:
<QuerySet [('平凡的世界', Decimal('125.00')), ('平凡的世界2', Decimal('105.00')), ('秦腔',Decimal('1005.00')), ('秦腔', Decimal('1005.00')), ('秦腔', Decimal('1005.00'))]> <QuerySet [('平凡的世界', Decimal('125.00')), ('平凡的世界2', Decimal('105.00')), ('秦腔',Decimal('1005.00')), ('秦腔', Decimal('1005.00')), ('秦腔', Decimal('1005.00'))]>
# 練習: 查詢人民出版社出版過的全部書籍的名字以及做者的姓名 # 正向查詢 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") # 練習: 手機號以151開頭的做者出版過的全部書籍名稱以及出版社名稱 # 方式1: queryResult=Book.objects .filter(authors__authorDetail__telephone__regex="151") .values_list("title","publish__name") # 方式2: ret=Author.objects .filter(authordetail__telephone__startswith="151") .values("book__title","book__publish__name")
反向查詢時,若是定義了related_name,則使用 related_name替換表名,例如:
publish = ForeignKey(Blog, related_name='bookList')
練習:
# 練習: 查詢人民出版社出版過的全部書籍的名字與價格(一對多) # 反向查詢 再也不按表名:book,而是related_name:bookList queryResult=Publish.objects .filter(name="人民出版社") .values_list("bookList__title","bookList__price")
經過對QuerySet進行計算,返回一個聚合值的字典,aggregate()中每個參數都指定一個包含在字典中的返回值。即在查詢集上生成聚合。
總結:跨表分組查詢的本質就是將關聯表join成一張表,再按照單表的思路進行分組查詢。
aggregate()字句的參數描述了咱們想要計算的聚合值。aggregate() 是QuerySet的一個終止子句,意思是它返回一個包含一些鍵值對的字典,鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。若是你想要爲聚合值指定一個名稱,能夠向聚合子句提供它。
from django.db.models import Avg, Min, Sum, Max def select_data(request): # 好比你想要計算全部在售的書的平均價錢 # Django 提供了一種方式描述全部圖書的集合 # 在下面的例子中,aggregate()計算的Book模型中price字段的平均值 res1 = Book.objects.all().aggregate(Avg('price')) print(res1) #{'price__avg': 561.5} # 若是想要爲聚合值指定一個名稱,能夠向聚合子句提供它。 res2 = Book.objects.aggregate(avergae_price=Avg('price')) print(res2) # {'avergae_price': 561.5} # 若是你想知道全部圖書價格的最大值和最小值,能夠這樣查詢 res3 = Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) print(res3) # {'price__avg': 561.5, 'price__max': Decimal('1005.00'), 'price__min': Decimal('105.00')} return HttpResponse("select data OK")
能夠經過計算查詢結果中每個對象所關聯的對象集合,從而獲得總計值(也能夠是平均值或者總和),即爲查詢集的每一項生成聚合。
查詢各個做者出的書的總價格,這裏就涉及到分組了,分組條件是authors_name
查詢各個出版社最便宜的書價是多少
from django.db.models import Avg, Min, Sum, Max def select_data(request): # 查詢各個做者出的書的總價格,這裏涉及分組,分組條件是authors_name res1 = Book.objects.values("authors__name").annotate(Sum('price')) print(res1) # 查詢各個出版社最便宜的書架是多少 res2 = Book.objects.values("publish__name").annotate(Min("price")) print(res2) return HttpResponse("select data OK")
結果以下:
<QuerySet [{'authors__name': 'james', 'price__sum': Decimal('2010.00')}, {'authors__name':'durant', 'price__sum': Decimal('2010.00')}, {'authors__name': None, 'price__sum': Decimal('1359.00')}]> <QuerySet [{'publish__name': '機械出版社', 'price__min': Decimal('105.00')}, {'publish__name':'清華出版社', 'price__min':Decimal('124.00')}]>
1,練習:統計每個出版社裏最便宜的書籍
publishList = Publish.objetcs.annotate(minPrice=Min('book__price")) for publish_obj in publishList: print(publish_obj.name, publish_obj.MinPrice)
annotate的返回值是QuerySet,若是不想遍歷對象,能夠用上 valuelist
queryResult= Publish.objects .annotate(MinPrice=Min("book__price")) .values_list("name","MinPrice") print(queryResult)
對應的SQL代碼以下:
''' SELECT "app01_publish"."name", MIN("app01_book"."price") AS "MinPrice" FROM "app01_publish" LEFT JOIN "app01_book" ON ("app01_publish"."nid" = "app01_book"."publish_id") GROUP BY "app01_publish"."nid", "app01_publish"."name", "app01_publish"."city", "app01_publish"."email" '''
2,練習:統計每一本書的做者個數
ret = Book.objects.annotate(authorsNum=Count('authors__name'))
3,統計每一本以py開頭的書籍的做者個數
queryResult=Book.objects.filter(title__startswith="Py") .annotate(num_authors=Count('authors'))
4,統計不止一個做者的圖書:
queryResult=Book.objects.annotate(num_authors=Count('authors')) .filter(num_authors__gt=1)
5,根據一本圖書做者數量的多少對查詢集QuerySet進行排序
Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
6,查詢各個做者出的書的總價格
# 按author表的全部字段 group by queryResult=Author.objects.annotate(SumPrice=Sum("book__price")) .values_list("name","SumPrice") print(queryResult)
僅僅靠着單一的關鍵字參數查詢已經很難知足查詢要求。此時Django爲咱們提供了F和Q查詢:
F()的實例能夠在查詢中引用字段,來比較同一個model實例中兩個不一樣字段的值。
# 查詢評論數大於收藏數的書籍 from django.db.models import F Book.objects.filter(commnetNum__lt=F('keepNum'))
Django支持F() 對象之間以及F()對象和常數之間的加減乘除和取模的操做
# 查詢評論數大於收藏數2倍的書籍 Book.objects.filter(commnetNum__lt=F('keepNum')*2)
修改操做也可使用F函數,好比把每一本書的價格提升10元
def update_use_F(request): # F 使用查詢條件的值,專門取對象中某列值的操做 from django.db.models import F # models.Tb1.objects.update(num=F('num') + 1) res1 = Book.objects.update(price = F('price') + 10) print(res1) return HttpResponse("update use F OK")
操做以前:
操做以後:
filter()等方法中的關鍵字參數查詢都是一塊兒「AND」的,若是你須要執行更復雜的查詢(例如OR語句),你可使用Q 對象。
from django.db.models import Q Q(title__startswith='Py')
Q 對象可使用& 和| 操做符組合起來。當一個操做符在兩個Q 對象上使用時,它產生一個新的Q 對象。
bookList=Book.objects.filter(Q(authors__name="james")|Q(authors__name="durant"))
等同於SQL WHERE字句:
WHERE name ="james" OR name ="durant"
你能夠組合& 和| 操做符以及使用括號進行分組來編寫任意複雜的Q 對象。同時,Q 對象可使用~ 操做符取反,這容許組合正常的查詢和取反(NOT) 查詢:
bookList=Book.objects.filter(Q(authors__name="james") & ~Q(publishDate__year=2017)).values_list("title")
查詢函數能夠混合使用Q 對象和關鍵字參數。全部提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND」在一塊兒。可是,若是出現Q 對象,它必須位於全部關鍵字參數的前面。例如:
bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python" )
# F 使用查詢條件的值,專門取對象中某列值的操做 # from django.db.models import F # models.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>] # 二、能夠組合使用&,|操做符,當一個操做符是用於兩個Q的對象,它產生一個新的Q對象。 Q(title__startswith='P') | Q(title__startswith='J') # 三、Q對象能夠用~操做符放在前面表示否認,也可容許否認與不否認形式的組合 Q(title__startswith='P') | ~Q(pub_date__year=2005) # 四、應用範圍: # 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 question 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 # 五、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)))
刪除方法就是delete() 它運行時當即刪除對象而不返回任何值。例如:
model_obj.delete()
你能夠一次性刪除多個對象,每一個QuerySet都有一個delete()方法,它一次性刪除QuerySet中全部的對象。
例以下面的代碼將刪除pub_date是2005年的Entry對象:
Entry.objects.filter(pub_date__year=2005).delete()
在Django刪除對象時,會模仿SQL約束ON DELETE CASCADE的行爲,換句話說,刪除一個對象時也會刪除與它相關聯的外鍵對象。例如:
b = Blog.objects.get(pk=1) # This will delete the Blog and all of its Entry objects. b.delete()
要注意的是:delete() 方法就是QuerySet上的方法,但並不適用於Manager自己。這是一種保護機制,是爲了不意外的調用Entry.objects.delete() 方法致使全部的記錄被誤刪除。若是你確認要刪除全部的對象,那麼你必須顯示的調用:
Entry.objects.all().delete()
若是不想級聯刪除,能夠設置爲:
pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL, blank=True, null=True)
若是是多對多的關係:remove() 和 clear()方法
多對多刪除的兩個重要參數:clear() 清空數據 remove() 刪除數據
#正向 book = models.Book.objects.filter(id=1) #刪除第三張表中和女孩1關聯的全部關聯信息 book.author.clear() #清空與book中id=1 關聯的全部數據 book.author.remove(2) #能夠爲id book.author.remove(*[1,2,3,4]) #能夠爲列表,前面加* #反向 author = models.Author.objects.filter(id=1) author.book_set.clear() #清空與boy中id=1 關聯的全部數據
Book.objects.filter(title__startswith="py").update(price=120)
此外,update() 方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。
#---------------- update方法直接設定對應屬性---------------- models.Book.objects.filter(id=3).update(title="PHP") ##sql: ##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3) #--------------- save方法會將全部屬性從新設定一遍,效率低----------- obj=models.Book.objects.filter(id=3)[0] obj.title="Python" obj.save() # SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", # "app01_book"."color", "app01_book"."page_num", # "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1; # # UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556, # "publisher_id" = 1 WHERE "app01_book"."id" = 3;
在這個例子裏咱們能夠看到Django的save()方法更新了不只僅是title列的值,還有更新了全部的列。若title之外的列有可能會被其餘的進程所改動的狀況下,只更改title列顯然是更加明智的。更改某一指定的列,咱們能夠調用結果集(QuerySet)對象的update()方法,與之等同的SQL語句變得更加高效,而且不會引發競態條件。
此外,update()方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。
注意:這裏由於update返回的是一個整型,因此無法用query屬性;對於每次建立一個對象,想顯示對應的raw 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', }, } }
注意:若是是多對多的改:
obj=Book.objects.filter(id=1)[0] author=Author.objects.filter(id__gt=2) obj.author.clear() obj.author.add(*author)