昨日內容回顧:css
1. {% include '' %} 2. extend base.html: <html> ..... ..... ..... {% block content%} {% endblock%} </html> index.html: {% extend 'base.html'%} <p>python</p> {% block content%} <p>hello</p> {% endblock%} 子網頁,也能夠設置css和js。好比: {% block css %} {% endblock %} {% block js %} {% endblock %} models:ORM class ----- 表 屬性變量 ----- 字段名稱 屬性值 ----- 字段約束 對象 ------ 記錄 建立表的流程 1. 在models裏設計模型類 class Book(models.Model): nid=models.AutoField(primary_key=True) ... 2. 更改數據庫爲mysql,在settings中: 2.1 先註冊app INSTALLED_APPS = [ ... 'app01', ] 2.2 更改數據庫引擎 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 數據庫引擎mysql 'NAME': 'book', # 你要存儲數據的庫名,事先要建立之 'USER': 'root', # 數據庫用戶名 'PASSWORD': '', # 密碼 'HOST': 'localhost', # 主機 'PORT': '3306', # 數據庫使用的端口 } } 3. 建立數據庫book 4. 必須安裝2個模塊 pip3 install pymysql pip3 install mysqlclient 5. python manage.py makemigrations(同步) python manage.py migrate(執行sql)
返回值是添加的model對象html
create方法的返回值book_obj就是插入book表中的python葵花寶典這本書籍紀錄對象python
book_obj=Book.objects.create(title="python葵花寶典",state=True,price=100,publish="蘋果出版社",
pub_date="2012-12-12")
book_obj=Book(title="python葵花寶典",state=True,price=100,publish="蘋果出版社",pub_date="2012-12-12") book_obj.save()
舉例:mysql
修改settings.py,打印orm轉換過程當中的sql。最後一行,添加以下內容:git
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
修改urls.py,增長add路徑sql
from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('add/', views.add), ]
models.py內容以下:數據庫
class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32, unique=True) price = models.DecimalField(max_digits=8, decimal_places=2) pub_date = models.DateField() publish = models.CharField(max_length=32)
表已經生成了,可是表記錄是空的。django
Pycharm有自帶的工具,能夠操做MySQL。點擊右側的Databaseapp
點擊加號-->Data Source-->MySQLide
這裏提示要安裝MySQL驅動,點擊旁邊的Download
正在下載安裝
出現下面的效果,表示安裝成功。
點擊測試鏈接,出現Successful,表示鏈接成功。
雙擊展開,就能夠看到app01_book表了。雖然models.py裏面的類名是Book,可是實際建立的表名是應用名+models.py裏面的類名。用下劃線分割,大寫字母會變成小寫。
修改views.py,增長add視圖函數。
注意,須要導入models模塊
這裏面的title,price...變量是和Book類的屬性是一一對應的,不然會報錯。
from django.shortcuts import render,HttpResponse
from app01.models import Book
# Create your views here.
def add(request):
book = Book(title="北京摺疊",price="11.11",pub_date="2012-12-12",publish="蘋果出版社")
book.save()
return HttpResponse("添加成功")
這是第一種方式:實例化一個對象,並傳參。
pub_date的值,必須是xxxx_xx_xx格式。用下劃線分隔,其餘符合是不能夠的。
訪問網頁,效果以下:
雙擊右邊的book表,查看錶記錄。點擊刷新按鈕,就能夠看到數據了。
注意:只要django執行了視圖函數的那2句代碼,就能夠插入一條記錄。
並不必定,非要在views.py裏面才行。具體放在哪裏,是根據業務邏輯來處理。
通常請求下,是放在views.py裏面。
查看控制檯輸出信息,會看到一條insert語句
(0.001) INSERT INTO `app01_book` (`title`, `price`, `pub_date`, `publish`) VALUES ('北京摺疊', '11.11', '2012-12-12', ' 蘋果出版社'); args=['北京摺疊', '11.11', '2012-12-12', '蘋果出版社']
那麼book.save(),就是執行上面這句SQL,來插入一條記錄的。
第二種方式:推薦使用
objects:表示管理器。
Book.objects:表示管理book表。
book.objects.create:表示增長操做。
def add(request): book = Book.objects.create(title="放風箏的人", price="14.11", pub_date="2017-12-12", publish="蘋果出版社") print(book) print(book.title) return HttpResponse("添加成功")
這種方式,一行代碼,就搞定了。
create是有返回值的,create內部裏面有save。
訪問add頁面
查看控制檯
(0.002) INSERT INTO `app01_book` (`title`, `price`, `pub_date`, `publish`) VALUES ('放風箏的人', '14.11', '2017-12-12', '蘋果出版社'); args=['放風箏的人', '14.11', '2017-12-12', '蘋果出版社'] Book object (2) 放風箏的人
create的返回值是一個類對象,好比:Book object
book_obj.title的返回值,就是create裏面的值。
create執行的SQL和save是同樣的。區別是create代碼更精簡!
若是create少一個字段,好比price呢?測試一下
def add(request): book_obj = Book.objects.create(title="放風箏的人2",pub_date="2018-12-12",publish="蘋果出版社") return HttpResponse("添加成功")
訪問頁面,提示price不容許爲空
更改models.py裏面的price屬性,設置價格屬性爲空
添加字段is_pub,表示是否發佈
class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32, unique=True) price = models.DecimalField(max_digits=8, decimal_places=2,null=True) pub_date = models.DateField() publish = models.CharField(max_length=32) is_pub = models.BooleanField()
Pycharm有一個工具,不一樣執行繁瑣的同步命令
Tools-->Run manage.py Task...
輸入ma,就會有提示信息。選擇makemigrations,直接回車
最後輸出以下信息
意思就是is_pub字段必須設置一個默認值
從新修改models.py下的Book類,增長默認值
is_pub = models.BooleanField(default=False)
關閉下面的小窗口,從新運行命令makemigrations
輸出下面信息,表示成功了
執行migrate
查看錶記錄,發現多了一個is_pub字段。BooleanField對應的MySQL類型是tinyint(1)
那麼False對應的值是0,true對應的值是1。
再次刷新頁面,就能夠了
查看錶記錄,點擊刷新按鈕
再次刷新頁面,會報錯!由於title字段是惟一的。
修改views裏面的add視圖函數
book_obj = Book.objects.create(title="放風箏的人3", pub_date="2018-12-12", publish="蘋果出版社")
再次刷新頁面,就能夠了。查看錶記錄,刷新一下
注意:在開發項目時,最好打開日誌,這樣能夠查看ORM轉換的SQL語句,方便後面的調試。
<1> all(): 查詢全部結果 <2> filter(**kwargs): 它包含了與所給篩選條件相匹配的對象 <3> get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個, 若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。 <4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象 <5> order_by(*field): 對查詢結果排序 <6> reverse(): 對查詢結果反向排序 <8> count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。 <9> first(): 返回第一條記錄 <10> last(): 返回最後一條記錄 <11> exists(): 若是QuerySet包含數據,就返回True,不然返回False <12> values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列 model的實例化對象,而是一個可迭代的字典序列 <13> values_list(*field): 它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列 <14> distinct(): 從返回結果中剔除重複紀錄
它返回的是QuerySet數據類型對象,它是django orm 特有的數據類型。
數據格式爲:[model對象1,model對象2,model對象3 ...]
它和下面的 animal_list相似。先是一個列表,列表的元素是一個對象
class Annimal(object): def __init__(self, name, age): self.name = name self.age = age def call(self): return "汪汪汪" dog = Annimal("旺財", 3) cat = Annimal("小雪", 4) duck = Annimal("小黃", 5) animal_list = [dog, cat, duck]
一個對象,就是一條記錄。有多少條記錄,就有多少個對象。
舉例:
修改urls.py,增長query路徑
urlpatterns = [ path('admin/', admin.site.urls), path('add/', views.add), path('query/', views.query), ]
修改views.py,增長query視圖函數
def query(request): ret = Book.objects.all() print(ret) return HttpResponse("查詢成功")
訪問頁面,效果以下:
查看控制檯輸出信息:
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` LIMIT 21; args=()
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (5)>]>
它執行的sql,就是select...。返回結果是一個QuerySet數據類型
它是一個列表,裏面放了多個對象。個數取決於返回的行數!
QuerySet和model對象的區別:
只有model對象,才能調用屬性。
queryset不能直接調用屬性,由於它是一個列表。
既然是列表,就可使用for循環,打印title屬性。
修改query視圖函數
def query(request): book_list = Book.objects.all() print(book_list) for obj in book_list: print(obj.title) # 打印title屬性 return HttpResponse("查詢成功")
刷新頁面,查看控制檯,就會有4個書名
北京摺疊
放風箏的人
放風箏的人2
放風箏的人3
filter能夠用指定條件來查詢,它會返回一條或者多條記錄。
它的返回值是QuerySet數據類型對象
舉例:查看標題爲北京摺疊的記錄
修改query視圖函數
def query(request): ret = Book.objects.filter(title='北京摺疊') print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯信息
(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`title` = '北京摺疊' LIMIT 21; args=('北京摺疊',) <QuerySet [<Book: Book object (1)>]>
它執行的sql,是用了where條件的。
注意,下面這行代碼,不能直接執行
print(ret.price)
刷新頁面,報錯。QuerySet不能直接調用屬性,即便它只有一個對象
雖然能夠經過切片來調用屬性,可是不推薦使用。
由於它的長度是不固定的。
須要使用for循環來執行。
first用來取一條記錄,若是返回結果有多條,只會取第一條。
它的返回結果是model對象。
修改query視圖函數
def query(request): obj = Book.objects.all().first() print(obj) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`nid` ASC LIMIT 1; args=() Book object (1) 北京摺疊
查看sql,發現它使用order by排序。對主鍵nid,作了升序,而且使用limit 1返回一條結果。
ret的返回結果一個是model對象,那麼就能夠直接調用對象了。因此輸出:北京摺疊
學習API接口,重要的是它的返回值是什麼
last用來取最後一條記錄,若是返回結果有多條,只會取最後一條。
它的返回結果是model對象。能夠直接調用屬性!
修改query視圖函數
def query(request): obj = Book.objects.all().last() print(obj) print(obj.title) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.002) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`nid` DESC LIMIT 1; args=() Book object (5) 放風箏的人3
查看sql,發現它使用order by排序。對主鍵nid,作了降序,而且使用limit 1返回一條結果。
因此最後輸出:放風箏的人3
還能夠對all()進行切片操做
def query(request): obj = Book.objects.all()[1:3] print(obj) for i in obj: print(i.title) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` LIMIT 2 OFFSET 1; args=() <QuerySet [<Book: Book object (2)>, <Book: Book object (3)>]> (0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` LIMIT 2 OFFSET 1; args=() 放風箏的人 放風箏的人2
[1:3],返回2條記錄。切片原則:顧頭不顧尾。
返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
它的返回結果是一個model對象。
舉例:查詢nid爲1的記錄
修改query視圖函數‘
def query(request): obj = Book.objects.get(nid=2) print(obj) print(obj.title) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`nid` = 2; args=(2,) Book object (2) 放風箏的人
查看sql,發現它對應的where條件是nid = 2。返回結果的title屬性爲:放風箏的人
舉例:查詢結果大於1時
查看錶記錄,修改第3條記錄的價格爲14.11,並點擊上面的提交按鈕
修改query視圖函數,使用get查詢價格等於14.11的記錄。
def query(request): obj = Book.objects.get(price=14.11) print(obj) return HttpResponse("查詢成功")
刷新頁面,報錯!提示返回結果過多,不能大於2條。
舉例:查詢結果大於1時,也就是記錄不存在時
修改query視圖函數,查詢價格等於110
def query(request): obj = Book.objects.get(price=110) print(obj) return HttpResponse("查詢成功")
刷新頁面,報錯!提示查詢結果不存在
下面的代碼,也能夠返回一條記錄
obj = Book.objects.filter(nid=2).first()
可是使用first,它會執行order by。上面的代碼轉爲SQL爲:
SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`nid` = 2 ORDER BY `app01_book`.`nid` ASC LIMIT 1;
那麼它的效果不如直接使用get!就一臺記錄,還排序幹啥?
總結:
使用get有且只有一個結果時纔有意義。
推薦使用get時,利用主鍵查詢,由於主鍵是惟一的。
exists用來作排除的,它的返回結果是QuerySet
舉例:查詢價格不等於100的
修改query視圖函數
def query(request): obj = Book.objects.exclude(price=100) print(obj) for i in obj: print(i.title,i.price) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (5)>]> (0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE NOT (`app01_book`.`price` = '100' AND `app01_book`.`price` IS NOT NULL); args=(Decimal('100'),) 北京摺疊 11.11 放風箏的人 14.11 放風箏的人2 14.11 放風箏的人3 None
查看sql,發現它對應的where條件用了Not,返回結果是QuerySet
order_by,默認是升序,它的返回結果是QuerySet
舉例:查詢全部書籍,按照價格排序
修改表記錄,效果以下:
修改query視圖函數
def query(request): obj = Book.objects.order_by("price") print(obj) for i in obj: print(i.title,i.price) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: Book object (5)>, <Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>]> (0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`price` ASC; args=() 水滸傳 11.00 北京摺疊 11.11 放風箏的人 14.11 西遊記 233.00
若是指定的字段值爲空,則按照主鍵排序。
每次for循環查看結果,太麻煩了。能夠在models.py裏面增長一個__str__方法。
修改models.py,增長__str__方法,完整代碼以下:
from django.db import models # Create your models here. class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32, unique=True) price = models.DecimalField(max_digits=8, decimal_places=2,null=True) pub_date = models.DateField() publish = models.CharField(max_length=32) is_pub = models.BooleanField(default=False) def __str__(self): return '{}:{}'.format(self.title,self.price)
修改views.py下的query方法,代碼以下:
def query(request): obj = Book.objects.order_by("price") print(obj) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`price` ASC LIMIT 21; args=()
<QuerySet [<Book: 水滸傳:11.00>, <Book: 北京摺疊:11.11>, <Book: 放風箏的人:14.11>, <Book: 西遊記:233.00>]>
能夠直接看到title和價格!
注意:只有QuerySet數據類型對象,才能調用order_by
它的返回結果是QuerySet
舉例:
修改query方法
def query(request): obj = Book.objects.all().order_by("price").reverse() print(obj) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: 西遊記:233.00>, <Book: 放風箏的人:14.11>, <Book: 北京摺疊:11.11>, <Book: 水滸傳:11.00>]> (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` ORDER BY `app01_book`.`price` DESC LIMIT 21; args=()
它的sql語句用的是desc
它的返回結果數據類型是int
它是queryset的終止函數。爲何呢?由於它不能進行鏈式操做!
下面這種,就屬於鏈式操做。由於queryset能夠調用API接口,只要前一個接口的返回值是queryset,它能夠能夠一直調用API接口,除非遇到返回值不是queryset的狀況下,鏈式操做,才能夠終止。由於count的返回值是int,因此到這裏,就結束了!不能再調用API接口了!
Book.objects.all().filter(price__gt=100).order_by("pirce").count()
舉例:
修改query視圖函數
def query(request): obj = Book.objects.all().count() print(obj) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
4 (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT COUNT(*) AS `__count` FROM `app01_book`; args=()
obj的返回結果爲4
它的返回結果是一個布爾值
舉例:若是表裏面有書,輸入ok,不然輸出none
修改query視圖函數,使用常規方法
def query(request): ret = Book.objects.all() if ret: print('ok') return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
ok (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None (0.001) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book`; args=()
ret結果爲ok,它使用全表查詢,可是這樣有一個bug
若是數據庫有1000萬本,這樣一查,數據庫就崩潰了。
修改query視圖函數,使用exists
def query(request): ret = Book.objects.all().exists() if ret: print('ok') return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
ok (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.001) SELECT (1) AS `a` FROM `app01_book` LIMIT 1; args=()
ret結果爲ok,它用limit 1。它只查詢了一條記錄!
即便數據庫記錄過多,也不影響。這樣纔是合理的!
上述這些API方法,都是QuerySet在調用
下面即將講到的values,values_list,distinct。是一系列操做!
它是一個特殊的QuerySet,運行後獲得的並非一系列model的實例化對象,而是一個可迭代的字典序列
它的返回結果是一個特殊的QuerySet,列表每個元素都是字典
除了使用for循環以外,還有一個更好的方式。使用values,它內部封裝了for循環
舉例:查詢全部書籍名稱
修改query視圖函數
def query(request): ret = Book.objects.all().values("title") print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.000) SELECT `app01_book`.`title` FROM `app01_book` LIMIT 21; args=() <QuerySet [{'title': '北京摺疊'}, {'title': '放風箏的人'}, {'title': '水滸傳'}, {'title': '西遊記'}]>
values返回的是QuerySet,列表的每個元素都是字典。
values能夠接收多個參數,好比
ret = Book.objects.all().values("title","price")
字典的key,就是參數。一個字典,對應一條記錄。
跟上面講的QuerySet區別就在於:
不加values,QuerySet存放的是model對象。
加了values以後,QuerySet存放的是字典。
查詢某一個字段時,推薦使用values
它與values()很是類似,它返回的是一個元組序列
它的返回結果是一個特殊的QuerySet,列表每個元素都是元組
舉例:
修改query視圖函數
def query(request): book_list = Book.objects.all().values_list("title","price","pub_date") print(book_list) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.000) SELECT `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date` FROM `app01_book` LIMIT 21; args=() <QuerySet [('北京摺疊', Decimal('11.11'), datetime.date(2012, 12, 12)), ('放風箏的人', Decimal('14.11'), datetime.date(2017, 12, 12)), ('西遊記', Decimal('233.00'), datetime.date(2018, 7, 1)), ('水滸傳', Decimal('11.00'), datetime.date(2018, 7, 2))]>
values_list和values的區別在於:values_list的類型是元組,vallues是字典。
它的返回結果是QuerySet,注意:是一個常規的QuerySet
修改表記錄,將前2本書的價格修改成同樣的。
使用原生sql查詢價格,去除重複的值
mysql> select distinct(price) from app01_book; +--------+ | price | +--------+ | 100.00 | | 233.00 | | 11.00 | +--------+ rows in set (0.00 sec)
若是使用distinct對主鍵作去重,是沒有意義的。由於主鍵是惟一的!
mysql> select distinct(nid) from app01_book; +-----+ | nid | +-----+ | 1 | | 2 | | 5 | | 3 | +-----+ rows in set (0.01 sec)
對全部字段作去重,也是沒有意義的,由於每一條記錄,不可能有重複的,這不還有主鍵嘛
修改query視圖函數
def query(request): ret = Book.objects.all().distinct() print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: 北京摺疊:100.00>, <Book: 放風箏的人:100.00>, <Book: 西遊記:233.00>, <Book: 水滸傳:11.00>]> (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT DISTINCT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` LIMIT 21; args=()
全部記錄都有了,毫無心義
舉例:查看全部書籍的價格,結果是不重複的
修改query視圖函數
def query(request): ret = Book.objects.all().values("price").distinct() print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.000) SELECT DISTINCT `app01_book`.`price` FROM `app01_book` LIMIT 21; args=() <QuerySet [{'price': Decimal('100.00')}, {'price': Decimal('233.00')}, {'price': Decimal('11.00')}]>
舉例:查看全部書籍的價格以及出版社,價格和出版社同時不能重複
修改query視圖函數
def query(request): ret = Book.objects.all().values("price","publish").distinct() print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [{'publish': '蘋果出版社', 'price': Decimal('100.00')}, {'publish': '橘子出版社', 'price': Decimal('233.00')}, {'publish': '橘子出版社', 'price': Decimal('11.00')}]> (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.001) SELECT DISTINCT `app01_book`.`price`, `app01_book`.`publish` FROM `app01_book` LIMIT 21; args=()
發現結果只有3條,它使用了組合去重。2個字段,同時不惟一!
Book.objects.filter(price__in=[100,200,300]) Book.objects.filter(price__gt=100) Book.objects.filter(price__lt=100) Book.objects.filter(price__range=[100,200]) Book.objects.filter(title__contains="python") Book.objects.filter(title__icontains="python") Book.objects.filter(title__startswith="py") Book.objects.filter(pub_date__year=2012)
舉例:查詢價格大於100的
不能這麼寫
ret = Book.objects.filter(price>100)
正確寫法:
def query(request): ret = Book.objects.filter(price__gt=100) print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: 西遊記:233.00>]> (0.001) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` > '100' LIMIT 21; args=(Decimal('100'),)
價格大於100的,只有西遊記
舉例:查詢價格小於100的
修改query視圖函數
def query(request): ret = Book.objects.filter(price__lte=100) print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: 北京摺疊:100.00>, <Book: 放風箏的人:100.00>, <Book: 水滸傳:11.00>]> (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT VERSION(); args=None (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` <= '100' LIMIT 21; args=(Decimal('100'),)
價格小於等於100的,有北京摺疊,放風箏的人,水滸傳
舉例:查詢價格小於等於100的
修改query視圖函數
def query(request): ret = Book.objects.filter(price__gte=100) print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: 北京摺疊:100.00>, <Book: 放風箏的人:100.00>, <Book: 西遊記:233.00>]> (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.001) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` >= '100' LIMIT 21; args=(Decimal('100'),)
價格小於等於100的,有北京摺疊,放風箏的人,西遊記
舉例:查詢價格分別等於100,200,300的記錄
修改query視圖函數
def query(request): ret = Book.objects.filter(price__in=[100,200,300]) print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` IN ('200', '100', '300') LIMIT 21; args=(Decimal('200'), Decimal('100'), Decimal('300')) [27/Jun/2018 20:58:08] "GET /query/ HTTP/1.1" 200 12 <QuerySet [<Book: 北京摺疊:100.00>, <Book: 放風箏的人:100.00>]>
價格等於100,200,300的有 北京摺疊,放風箏的人
舉例:查詢價格在100到233之間的記錄
修改query視圖函數
def query(request): ret = Book.objects.filter(price__range=[100,300]) print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: 北京摺疊:100.00>, <Book: 放風箏的人:100.00>, <Book: 西遊記:233.00>]> (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`price` BETWEEN '100' AND '300' LIMIT 21;arg=(Decimal('100'),Decimal('300'))
價格在100到233之間的有 北京摺疊,放風箏的人,西遊記
舉例:查詢以"北京"開頭的書名有哪些
修改query視圖函數
def query(request): ret = Book.objects.filter(title__startswith="北京") print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`title` LIKE BINARY '北京%' LIMIT 21; args=('北京%',) <QuerySet [<Book: 北京摺疊:100.00>]>
以"北京"開頭的書名的有 北京摺疊
舉例:查詢書名包含「傳」的有哪些
修改query視圖函數
def query(request): ret = Book.objects.filter(title__contains="傳") print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
<QuerySet [<Book: 水滸傳:11.00>]> (0.001) SELECT @@SQL_AUTO_IS_NULL; args=None (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.001) SELECT VERSION(); args=None (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`title` LIKE BINARY '%傳%' LIMIT 21; args=('%傳%',)
書名包含「傳」的有 水滸傳
舉例:查詢出版日期是2018年的有哪些
修改query視圖函數
def query(request): ret = Book.objects.filter(pub_date__year="2018") print(ret) return HttpResponse("查詢成功")
刷新頁面,查看控制檯輸出信息:
(0.000) SELECT `app01_book`.`nid`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`pub_date`, `app01_book`.`publish`, `app01_book`.`is_pub` FROM `app01_book` WHERE `app01_book`.`pub_date` BETWEEN '2018-01-01' AND '2018-12-31' LIMIT 21; args=('2018-01-01', '2018-12-31') <QuerySet [<Book: 西遊記:233.00>, <Book: 水滸傳:11.00>]>
出版日期是2018年的有 西遊記,水滸傳
刪除方法就是 delete()。它運行時當即刪除對象而不返回任何值。例如:
model_obj.delete()
你也能夠一次性刪除多個對象。每一個 QuerySet 都有一個 delete() 方法,它一次性刪除 QuerySet 中全部的對象。
它的返回值是元組,元組第一個值,是執行狀態。1表示成功,0表示失敗!
例如,下面的代碼將刪除 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)
舉例:刪除價格等於100的
修改urls.py,增長delbook路徑
urlpatterns = [ path('admin/', admin.site.urls), path('add/', views.add), path('query/', views.query), path('change/', views.change), path('delbook/', views.delbook), ]
修改views.py,增長delbook視圖函數
注意:修改是基於查詢的結果來修改的。因此是先有查詢,再有修改!
def delbook(request): ret = Book.objects.filter(price=100).delete() print(ret) return HttpResponse("刪除成功")
訪問頁面
查看控制檯輸出信息:
(0.001) DELETE FROM `app01_book` WHERE `app01_book`.`price` = '100'; args=(Decimal('100'),) (1, {'app01.Book': 1})
輸出1,表示刪除成功!
查看錶記錄,點擊刷新按鈕,發現少了一條記錄!
QuerySet和model均可以調用delete
舉例:查詢價格小於100的,並將第一條記錄刪除
修改delbook視圖函數
def delbook(request): ret = Book.objects.filter(price__lte=100).delete() print(ret) return HttpResponse("刪除成功")
查看控制檯輸出信息:
(0.000) DELETE FROM `app01_book` WHERE `app01_book`.`price` <= '100'; args=(Decimal('100'),) [27/Jun/2018 21:41:49] "GET /delbook/ HTTP/1.1" 200 12 (1, {'app01.Book': 1})
輸出結果爲1,說明刪除成功了!
查看錶記錄,點擊刷新按鈕,發現少了一條記錄!
舉例3:根據url的id值,來刪除對應的記錄
若是url的id爲2,就刪除nid爲2的記錄
修改urls.py,爲delbook增長有名分組
注意:要導入re_path模塊,完整代碼以下:
from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('add/', views.add), path('query/', views.query), path('change/', views.change), re_path('delbook/(?P<id>\d+)', views.delbook), ]
修改delbook視圖函數
def delbook(request,id): ret = Book.objects.filter(nid=id).delete() print(ret) return HttpResponse("刪除成功")
訪問url: http://127.0.0.1:8000/delbook/3
查看控制檯輸出信息:
(0.001) DELETE FROM `app01_book` WHERE `app01_book`.`nid` = 3; args=(3,) (1, {'app01.Book': 1})
輸出結果爲1,說明刪除成功了!
查看錶記錄,點擊刷新按鈕,發現少了一條記錄!
若是刪除一條不存在的記錄呢?
訪問url:http://127.0.0.1:8000/delbook/4
查看控制檯輸出信息:
(0, {'app01.Book': 0}) (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.001) SELECT VERSION(); args=None (0.001) DELETE FROM `app01_book` WHERE `app01_book`.`nid` = 4; args=(4,)
輸出結果爲0,說明刪除失敗了!
可是頁面提示刪除成功是不對的。
修改delbook視圖函數
def delbook(request,id): ret = Book.objects.filter(nid=id).delete() print(ret) print(ret,type(ret)) if ret[0]: return HttpResponse("刪除成功") else: return HttpResponse("刪除失敗")
再次訪問url:http://127.0.0.1:8000/delbook/4
查看控制檯輸出信息:
(0, {'app01.Book': 0}) (0.001) SELECT @@SQL_AUTO_IS_NULL; args=None (0, {'app01.Book': 0}) <class 'tuple'> (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None (0.000) SELECT VERSION(); args=None (0.000) DELETE FROM `app01_book` WHERE `app01_book`.`nid` = 4; args=(4,)
它的返回值是一個元組,經過取第一個元素,就能夠獲得數字0。那麼就能夠進行if判斷了!
Book.objects.filter(title__startswith="py").update(price=120)
此外,update()方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。
update的返回值爲int。1表示成功,0表示失敗。
舉例:修改nid爲1的記錄,將價格修改成1000元
修改urls.py,增長change路徑
urlpatterns = [ path('admin/', admin.site.urls), path('add/', views.add), path('query/', views.query), path('change/', views.change), ]
修改views.py,增長change視圖函數
注意:修改是基於查詢的結果來修改的。因此是先有查詢,再有修改!
def change(request): nid = 1 ret = Book.objects.filter(nid=nid).update(price=1000) print(ret) return HttpResponse("修改爲功")
訪問頁面
查看控制檯輸出信息:
(0.001) UPDATE `app01_book` SET `price` = '1000.00' WHERE `app01_book`.`nid` = 1; args=('1000.00', 1) 1
舉例:修改西遊記的價格爲133以及is_pub修改成1
修改change視圖函數
def change(request): nid = 3 ret = Book.objects.filter(nid=nid).update(price=133,is_pub=1) print(ret) return HttpResponse("修改爲功")def change(request): nid = 3 ret = Book.objects.filter(nid=nid).update(price=133,is_pub=1) print(ret) return HttpResponse("修改爲功")
刷新頁面,查看控制檯輸出信息:
(0.001) UPDATE `app01_book` SET `price` = '133.00', `is_pub` = 1 WHERE `app01_book`.`nid` = 3; args=('133.00', True, 3) 1
ret的返回結果爲1,表示修改爲功!
查看錶記錄,點擊刷新按鈕,發現價格和is_pub已經修改了!