一、ORM -- 數據庫交互
參考地址:
ORM常用字段和參數:https://www.cnblogs.com/liuqingzheng/articles/9627915.html
Django-model進階:https://www.cnblogs.com/liuqingzheng/articles/9805991.html
8 Django 模型層(1) - Yuan先生 - 博客園
Django從入門到放棄 - 劉清政 - 博客園
SQL中的表與ORM直觀對比圖:ORM在python中是以類的方式定義的,在執行python時,類會轉換成對應的SQL語句。
1.1、首先學習,在Python中創建數據庫
1.1.1).首先在DB裡面創建庫:create database book_orm;
1.1.2).在Django項目裡面,設置settings.py文件
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'orm_19', # 要連接的數據庫,連接前需要創建好
'USER':'root', # 連接數據庫的用戶名
'PASSWORD':'123456', # 連接數據庫的密碼
'HOST':'127.0.0.1', # 連接主機,默認本級
'PORT':3306 # 端口 默認3306
}
}
# 手動創建數據庫
create DATABASE `sudada` default charset utf8;
# 備注: 制定utf8字符集
1.1.3).在Django項目裡面,設置models.py文件 (數據表結構)
class Book(models.Model): # Book可以理解為要創建的表名(實際創建時會附帶上Django應用的名稱)
id = models.AutoField(primary_key=True) # 主鍵:主鍵字段不可修改,如果你給某個對象的主鍵賦個新值實際上是創建一個新對象,並不會修改原來的對象。
title = models.CharField(max_length=32) # CharField用來存字符串的,對應varchar
pub_date = models.DateField() # 存日期的
price = models.DecimalField(max_digits=8, decimal_places=2) # 存價格的
publish = models.CharField(max_length=32) # CharField用來存字符串的,對應varchar
1.1.4).在windows命令行使用:python3 manage.py makemigrations 命令(生成一條記錄,並沒有提交到數據庫) 創建表:(步驟一)
1.1.4.1) 這一步會報錯,如下:這是由於使用了MySQL模塊導致的,在python3中,一般都是使用pymysql的,那麼我們就需要告訴Django要使用pymysql。
1.1.4.2) 在app01目錄下的__init__.py文件中或者在項目目錄下的__init__.py文件中定義如下代碼:告訴Django數據驅動使用pymysql
import pymysql
pymysql.install_as_MySQLdb()
1.1.4.3) 最後在使用python3 manage.py makemigrations命令 (生成一條記錄,並沒有提交到數據庫) 創建表即可
1.1.5.在windows命令行使用:python3 manage.py migrate 命令 (把生成的命令提交到數據庫執行) 創建表: (步驟二)
1.1.6.數據表創建完畢後,查看:
這些表裡面除了 "app01_book" (app01:應用名,book:表名,2者組合為了方便區分) 這張表是自己寫的,其他都是Django默認創建的。
1.1.7. 開啟Django項目,由於在models.py文件定義了創建表的數據類型,那麼訪問http://127.0.0.1:8000/即可創建數據類型(關系對象映射)
1.2 對數據庫內的表結構,做修改的操作
1.2.1.新增一條表結構 -- 在models.py文件中,直接新增一行表結構 (必須輸入默認內容及是否允許為空:default='egon',null=True ),然後執行 python3 manage.py makemigrations (生成一條記錄,並沒有提交到數據庫) 命令:
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
pub_date = models.DateField()
price = models.DecimalField(max_digits=8, decimal_places=2)
publish = models.CharField(max_length=32,default='egon',null=True) # default='egon':設置默認字符串,null=True:允許空值。
執行 python3 manage.py makemigrations 命令之後,會在migtations下生成一個文件:這個文件裡面記錄了,修改後的表結構。
operations = [
migrations.AddField(
model_name='book',
name='publish',
field=models.CharField(default='egon', max_length=32, null=True),
),
]
需要再次執行 python3 manage.py migrate (把生成的命令提交到數據庫執行) 創建表。
1.2.2.刪除一條表結構 -- 在models.py文件中,直接注釋掉一行表結構
class Book(models.Model):
id = models.AutoField(primary_key=True) # 生成一個主鍵:主鍵字段不可修改,如果你給某個對象的主鍵賦個新值實際上是創建一個新對象,並不會修改原來的對象。
title = models.CharField(max_length=32) # CharField 對應的就是varchar,用來存放字符串的
pub_date = models.DateField() # 日期格式
price = models.DecimalField(max_digits=8, decimal_places=2)
# publish = models.CharField(max_length=32)
然後執行 python3 manage.py makemigrations (生成一條記錄,並沒有提交到數據庫) 命令,會在migrations目錄下生產一個0001_initial.py文件,這個文件裡面記錄了,修改後的表結構。
operations = [
migrations.CreateModel(
name='Book',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('title', models.CharField(max_length=32)),
('pub_date', models.DateField()),
('price', models.DecimalField(decimal_places=2, max_digits=8)),
],
),
]
需要再次執行 python3 manage.py migrate (把生成的命令提交到數據庫執行) 創建表。
1.2、 如果想打印orm轉換過程中的sql,需要在settings中進行如下配置:DBUG模式
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預計如下:
SELECT `app01_study`.`id`, `app01_study`.`title`, `app01_study`.`pub_date`, `app01_study`.`price`, `app01_study`.`publish` FROM `app01_study` WHERE `app01_study`.`title` = '紅寶書' LIMIT 21; args=('紅寶書',)
[04/Mar/2019 22:46:39] "GET /select/ HTTP/1.1" 200 2
1.3 、單表操作-針對數據庫表的增、刪、改、查 學習地址:Django模型層 - 劉清政 - 博客園
1.3.1.添加數據 方式一:create方式
from app01.models import Book # 引用models.py文件內的Book類
def orm(request): # Book.objects表示"Book類"的一個管理器,通過這個管理器來實現"增,刪,改,查"
# 添加數據
# Book類,即models.py文件裡面定義的類
# title,pub_date,price,publish 即為表的字段
Book.objects.create(title='python',pub_date='2015-05-11',price=199,publish='人民出版社')
return HttpResponse('OK')
添加完畢後,查詢數據庫內容如下:
方式二:save方式,有返回值,就是Book對象
from app01.models import Book
def add(request):
book=Book(title='紅寶書',price=100,pub_date='2017-8-17',publish='人民')
book.save()
return HttpResponse('ok')
添加完畢後,查詢數據庫內容如下:
1.3.2.查詢數據
方式一:使用Book.objects.all()拿到所有對象,拿到的是一個QuerySet,裡面包含的所有的對象
from app01.models import Book
def orm(request):
# 查詢數據
book_list=Book.objects.all() # Book.objects.all()拿到的是一個"QuerySet"對象,(數據庫內的"app01_book"表,每一行數據都被實例化為一個對象)
for book in book_list: # 循環對象
print(book.title) # 打印對象的title,pub_date,price,publish等信息
print(book.pub_date)
print(book.price)
print(book.publish)
# linux
# 2013 - 05 - 11
# 299.00
# 人民出版社
return HttpResponse('OK')
方式二:查詢單個或多個條件 Study.objects.filter(title='西游記',id=5),拿到的是一個QuerySet,裡面包含的是查詢到的對象
from app01.models import Study
def select(request):
res=Study.objects.filter(title='西游記',id=5)
print(res) # res拿到的是"QuerySet"這個對象,<QuerySet [<Study: Study object (5)>]>
res_obj=Study.objects.filter(title='西游記',id=5).first() # 如果通過Study.objects.filter(title='西游記',id=5)取到多個值的話,那麼使用.first()只取第一個值
print(res_obj.title) # res_obj拿到的是"一行數據"這個對象,西游記
return HttpResponse('ok')
方式三:使用 Study.objects.get(title='西游記') 查詢的結果有且僅有一個,多一個或少一個都會報錯
from app01.models import Study
def select(request):
res_get=Study.objects.get(title='西游記')
print(res_get)
return HttpResponse('ok')
1.3.3.刪除數據
方式一:Book.objects.filter(id=1).delete() 把id=1的數據給刪掉
from app01.models import Study
def orm(request):
# 刪除數據
Study.objects.filter(id=1).delete() # filter為判斷條件,查找數據表"app01_book"內,id=1的數據,delete()刪除數據。
return HttpResponse('OK')
方式二:Study.objects.filter(title='紅寶書').first().delete() 如果Study.objects.filter(title='紅寶書')拿到的值為多個數據,那麼.first()就是只刪除第一個數據
from app01.models import Study
def select(request):
Study.objects.filter(title='紅寶書').first().delete()
return HttpResponse('ok')
1.3.4.修改數據
Study.objects.filter(title='西游記',id=5).update(title='蘇大大',id=5) 把title='西游記',id=5的數據修改為title='蘇大大',id=5
from app01.models import Study
def select(request):
Study.objects.filter(title='西游記',id=4).update(title='蘇大大',id=4) # 查找title='西游記',id=4的數據,然後修改為:title='蘇大大',id=4
return HttpResponse('ok')
1.3.5、ORM查詢API
<1> all(): 查詢所有結果,QuerySet
<2> filter(**kwargs): 它包含了與所給篩選條件相匹配的對象,QuerySet
<3> get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
<4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象
<5> order_by(*field): 對查詢結果排序('-id')
<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(): 從返回結果中剔除重復紀錄
1.3.6、查看ORM轉換對應的SQL執行過程(在setting.py文件內配置,然後查看請求日志就有對應的SQL)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
1.3.7、基於雙下劃線的模糊查詢
Book.objects.filter(price__in=[100,200,300]) # 字符串是否存在於這個列表內
Book.objects.filter(price__gt=100) # 大於
Book.objects.filter(price__lt=100) # 小於
Book.objects.filter(price__gte=100) # 大於等於
Book.objects.filter(price__lte=100) # 小於等於
Book.objects.filter(price__range=[100,200]) # 字符串是否存在於這個range內
Book.objects.filter(title__contains="python") # 字符串是否包含"python"
Book.objects.filter(title__icontains="python") # 字符串"python"不區分大小寫
Book.objects.filter(title__startswith="py") # 字符串以"py"開頭
Book.objects.filter(pub_date__year=2012) # 時間段在2012年的字符
學習多表查詢之前先查看下ORM的常用字段有哪些:常用字段和參數 - 劉清政 - 博客園
學習地址:Django模型層之多表操作 - 劉清政 - 博客園
二、多表操作 : 一對一,一對多,多對多(需要創建中間表才能描述多表之間的聯系)
實例:首先來假定下面這些概念,字段和關系
作者模型:一個作者有姓名和年齡。
作者詳細模型:把作者的詳情放到詳情表,包含生日,手機號,家庭住址等信息。作者詳情模型和作者模型之間是一對一的關系(one-to-one)
出版商模型:出版商有名稱,所在城市以及email。
書籍模型: 書籍有書名和出版日期,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關系就是多對多的關聯關系(many-to-many);一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關系(one-to-many)。
2.1、實例(偽代碼):根據多個表來分析,多表之間的對應關系
Publish # 出版社
Book # 書籍名稱(一對多)
Author # 書籍作者:Author與AuthorDetail表之間做了對應關系
AuthorDetail # 作者信息:Author與AuthorDetail表之間做了對應關系
Book2Author # 書籍與作者之間的對應關系(為了描述多對多之間的關系而創建的中間表)
CREATE TABLE publish(
id INT PRIMARY KEY auto_increment ,
name VARCHAR (20)
);
CREATE TABLE book(
id INT PRIMARY KEY auto_increment ,
title VARCHAR (20),
price DECIMAL (8,2),
pub_date DATE ,
publish_id INT ,
FOREIGN KEY (publish_id) REFERENCES publish(id)
);
CREATE TABLE authordetail(
id INT PRIMARY KEY auto_increment ,
tel VARCHAR (20)
);
CREATE TABLE author(
id INT PRIMARY KEY auto_increment ,
name VARCHAR (20),
age INT,
authordetail_id INT UNIQUE ,
FOREIGN KEY (authordetail_id) REFERENCES authordetail(id)
);
CREATE TABLE book2author(
id INT PRIMARY KEY auto_increment ,
book_id INT ,
author_id INT ,
FOREIGN KEY (book_id) REFERENCES book(id),
FOREIGN KEY (author_id) REFERENCES author(id)
)
2.2、在Django中:models.py文件中 (這個文件主要是使用ORM時,定義的一些類)
from django.db import models
# Create your models here.
# 這個文件主要是使用ORM時,定義的一些類。
# 多表操作 :一對一,一對多,多對多之間的關聯關系
# 書籍出版日期表
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()
# 書籍名稱表,與Publish表關聯
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
publish_date = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2)
# auto_now_add:插入數據的當前時間,auto_now:修改數據時的時間。
# "to='Publish'"表示和Publish表做關聯,to_field='nid'表示和表裡面的哪個字段做關聯
# on_delete=models.CASCADE:級聯刪除,只要是有(OneToOneField和ForeignKey)字段的,都得加。ManyToManyField不用加
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
# 多對多的中間表,書籍表和作者表做關聯
authors = models.ManyToManyField(to='Author')
# "ManyToManyField"(多對多):就相當於自動創建了中間表,真正到數據庫執行的就是創建一個中間表
"""
# 純SQL的寫法:
CREATE TABLE book2author(
id INT PRIMARY KEY auto_increment , # book2author本身的主鍵ID
book_id INT , # 字段 book_id
author_id INT , # 字段 author_id
FOREIGN KEY (book_id) REFERENCES book(id), # 字段 book_id 關聯book表下的id字段
FOREIGN KEY (author_id) REFERENCES author(id) # 字段 author_id author表下的id字段
)
# Django中的寫法:
class Book2Author(models.Model):
nid = models.AutoField(primary_key=True)
author_id = models.ForeignKey(to='Author',to_field='nid')
book_id = models.ForeignKey(to='Author',to_field='nid')
"""
def __str__(self): # 調用這個類的時候,會自動執行這個函數
return self.name
# 書籍對應的作者信息表,與AuthorDetail關聯(一對一)
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
# 一對一之間關聯:字段"authorDetail" 對應的就是'AuthorDetail'表的字段'nid',unique=True表示唯一約束,也就是說authorDetail只能對應一個值。
# on_delete=models.CASCADE:級聯刪除,只要是有(OneToOneField和ForeignKey)字段的,都得加。ManyToManyField不用加
# OneToOneField 內部實現的是一個FOREIGN KEY (authordetail_id) PEFERENCES authordetail(id)
authorDetail = models.OneToOneField(to='AuthorDetail',to_field='nid',unique=True,on_delete=models.CASCADE)
# 作者本身的信息表
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
phone = models.BigIntegerField()
addr = models.CharField(max_length=64)
生成的表如下:
注意事項:
1、表的名稱myapp_modelName,是根據 模型中的元數據自動生成的,也可以覆寫為別的名稱
2、id 字段是自動添加的
3、對於外鍵字段,Django 會在字段名上添加"_id" 來創建數據庫中的列名
4、這個例子中的CREATE TABLE SQL 語句使用PostgreSQL 語法格式,要注意的是Django 會根據settings 中指定的數據庫類型來使用相應的SQL 語句。
5、定義好模型之後,你需要告訴Django _使用_這些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中設置,在其中添加models.py所在應用的名稱。
6、外鍵字段 ForeignKey 有一個 null=True 的設置(它允許外鍵接受空值 NULL),你可以賦給它空值 None 。
2.3、執行命令創建表:makemigrations --> migrate
2.4、多表的操作--添加表記錄
2.4.1、一對多的數據新增
def mui_query(request):
# 一對多的數據新增
# 方式一:指定"publish_id"的方式,傳遞出版社的信息
book1 = Book.objects.create(name='紅樓夢',price=199,publish_date='2016-09-08',publish_id=1)
print(book1)
# 方式二:通過獲取出版社"對象",然後把該對象傳值給"publish"
pub=Publish.objects.filter(name='上海出版社').first()
book=Book.objects.create(name='金瓶梅',price=299,publish_date='2018-09-08',publish=pub)
print(book)
return HttpResponse('ok')
2.4.2、一對一數據新增
def mui_query(request):
# 一對一新增
# 方式一: 指定"authorDetail_id"的方式,傳遞書籍作者的信息
author=Author.objects.create(name='wsp',authorDetail_id=2)
print(author)
# 方式二:通過獲取書籍作者的對象,然後把對象傳值給“authorDetail” 注意:由於在models.py文件裡面設置了unique=True,所以只能一個Name對應一個authorDetail_id。如果一個authorDetail_id對應多個Name的話,就會出現1062等錯誤。
detail=AuthorDetail.objects.filter(addr='南京').first()
author = Author.objects.create(name='wsp', authorDetail=detail)
print(author)
return HttpResponse('ok')
# 補充,數據表內的ForeignKey字段,可以拿到對應表的對象,然後查詢數據
def index(request):
book=Book.objects.filter(name="西游").first()
print(book.publish) # 這裡拿到的是Publish表對象
print(book.publish.name) # 通過Publish表對象就可以查到Publish表對應的值
print(book.publish.city)
return HttpResponse("index")
2.4.2、多對多數據新增
book.authors.remove() 將某個特定的對象從被關聯對象集合中去除
book.authors.clear() 清空被關聯對象集合
book.authors.set() 先清空在設置
book.authors.add() 將某個對象添加到表內,可添加多個,用逗號分隔
def mui_query(request):
# 多對多新增
szq=Author.objects.filter(name='szq').first()
wsp=Author.objects.filter(name='wsp').first()
book = Book.objects.create(name='西游記', price='298', publish_date='1991-09-01', publish_id=1)
book.authors.add(szq) # book.authors是多對多的中間表,有2個字段,分別是"book_id"和"author_id"。
# book_id的值通過book.authors獲取
# author_id的值通過book.authors.add(szq)獲取,其中szq=Author.objects.filter(name='szq').first()
book.authors.add(szq,wsp) # 也可以傳遞2個值(一本書對應2個作者)
# book.authors.add(1,2) # 也可以傳對象對應的nid(主鍵數字)
return HttpResponse('ok')
2.4.3、刪除多表之間的關聯關系
def mui_query(request):
# 刪除一個關聯的數據
szq = Author.objects.filter(name='szq').first()
book = Book.objects.filter(name='西游記').first()
book.authors.remove(szq) # 把book.authors表裡面,關於book_id的值為'西游記',author_id的值為"szq"的數據刪除掉
# 刪除所有關聯的數據
szq = Author.objects.filter(name='szq').first()
book = Book.objects.filter(name='西游記').first()
book.authors.clear() # 把book.authors表裡面,關於book_id的值為'西游記'的數據全部刪除掉
# 修改一個關聯的數據(執行的過程為:先執行clear,然後在執行add)
book = Book.objects.filter(name='紅寶書').first()
book.authors.set([1,]) # 在book.authors表裡面,把book_id的值為'紅寶書'的這一條數據的author_id的值修改為1
return HttpResponse('ok')
2.4.4、核心:book.authors.all()是什麼? 在"book_authors" 表內,會根據"book_id"查找到對應的"author_id",然後根據"author_id"查找到"author"表內"author_id"對應的數據,並把這個數據封裝成一個對象。
def mui_query(request):
# 核心:book.authors.all()是什麼? # 拿到的是book.authors表的所有數據。
# 用法一:通過book.authors.all().values('name')直接獲取數據
book = Book.objects.filter(name='紅寶書').first()
ret=book.authors.all().values('name')
# book.authors.all().values() 這裡拿到的是一個字典: "{'nid': 1, 'name': 'sudada', 'authorDetail_id': 2}"
print(ret) # 獲取到author表內作者的信息, 通過book_authors表的book_id拿到對應的author_id,然後去authors表內拿到author_id對應的"name"值。
# 用法二:拿到一個個對象,依次取值
book = Book.objects.filter(name='紅寶書').first()
ret = book.authors.all().first() # 拿到的是Author這個對象
print(ret.name) # 拿到的是Author這個對象下的name的值
print(ret.authorDetail.phone) # 拿到的是Author這個對象下的authorDetail對象,通過authorDetail對象拿到對應phone的值
return HttpResponse('ok')
2.4、多表的操作--基於對象的跨表查詢(子查詢--先查一個表,然後根據這個表查詢另外一個表,2條SQL語句完成)
2.4.1、基於對象的多表查詢 (常用)
例子一:
def mui_query(request):
# 基於對象的多表查詢
# 查詢紅樓夢這本書作者的名字
book=Book.objects.filter(name='紅樓夢').first()
res=book.authors.all()
# 根據book_authors這張表的book_id查詢到對應的author_id字段,然後通過author_id找到對應的author表,然後取出對應的值。
for auth in res:
print(auth.name)
return HttpResponse('ok')
def mui_query(request):
# 基於對象的多表查詢
# 查詢紅樓夢這本書出版社的名字
book=Book.objects.filter(name='紅樓夢').first()
print(book.publish.name) # 北京出版社
return HttpResponse('ok')
2.4.2、什麼是正向查詢與反向查詢?
正向查詢:關聯字段在A表中,通過A表查詢B表叫做正向查詢
反向查詢:關聯字段在A表中,通過B表查詢A表叫做反向查詢(反向查詢按照表名小寫"book_set.all()"拿到所有對象)
正向查詢:通過表的字段.xxx
反向查詢:通過表名+"_set"
def mui_query(request):
'''
正向查詢:A表--查-->B表:關聯字段在A表中(正向查詢按照字段)
反向查詢:B表--查-->A表:B表中沒有關聯字段。(反向查詢按照表名小寫"book_set.all()"拿到所有對象)
'''
# 反向查詢例子:查看"北京出版社"出版了幾本書
pub=Publish.objects.filter(name__contains='北京出版社').first()
print(pub.book_set.all()) # 拿到對象:<QuerySet [<Book: 紅樓夢>, <Book: 水浒傳>, <Book: 西游記>, <Book: 三國>, <Book: 紅樓夢>]>
for pub_name in pub.book_set.all(): # 取出所有的值
print(pub_name)
# 紅樓夢
# 水浒傳
# 西游記
# 三國
# 紅樓夢
# 正向查詢例子:查詢紅樓夢這本書出版社的名字
book=Book.objects.filter(name='紅樓夢').first()
print(book.publish.name) # 北京出版社
return HttpResponse('ok')
2.4.3:一對一 正反向查詢,一對一反向查詢不需要"表名"+"_set",只需要寫表名即可。
def mui_query(request):
# 查詢作者"szq"的手機號,Author表-->AuthorDetail表,一對一正向查詢
author = Author.objects.filter(name='szq').first()
print(author.authorDetail.phone)
# 查詢手機號為"123456"對應的人的名字,AuthorDetail表-->Author表,一對一反向查詢(按照表名小寫)
# 一對一反向查詢不需要"表名"+"_set",只需要寫表名即可。
phone=AuthorDetail.objects.filter(phone='123456').first()
print(phone.author.name)
return HttpResponse('ok')
2.4.4:一對多 正反向查詢
def mui_query(request):
# 一對多的正向查詢
# 查詢"紅樓夢"這本書的出版社地址
book=Book.objects.filter(name="紅樓夢")
for city in book:
print(city.publish.city)
# 北京
# 北京
# 上海
# 一對多的反向查詢:通過 "表名"+"_set"關鍵字,即:book_set
# 北京出版社出版的書籍有哪些
pub=Publish.objects.filter(name='北京出版社').first()
for book in pub.book_set.all():
print(book.name)
# 紅樓夢
# 水浒傳
# 西游記
# 三國
# 紅樓夢
return HttpResponse('ok')
2.4.5::多對多 正反向查詢
# 多對多 正反向查詢
def mui_query(request):
# 查詢紅樓夢這本書作者的名字,Book表-->Author表,多對多正向查詢
book=Book.objects.filter(name='紅樓夢').first()
res=book.authors.all()
# 根據book_authors這張表的book_id查詢到對應的author_id字段,然後通過author_id找到對應的author表,然後取出對應的值。
for auth in res:
print(auth.name)
# 查詢作者名為"szq"寫的所有書籍,Author表-->Book表,多對多反向查詢
author=Author.objects.filter(name='szq').first()
print(author.book_set.all()) # 拿到對象: <QuerySet [<Book: 三國>, <Book: 紅樓夢>]>
for book_name in author.book_set.all(): # 取出所有的值
print(book_name)
# 三國
# 紅樓夢
return HttpResponse('ok')
2.6、多表的操作--基於雙下劃線的跨表查詢:join查詢(一條SQL語句完成查詢) 拿到的數據都是字典格式
2.6.1、一對一 正反向查詢
# 一對一 正反向查詢
def mui_query(request):
# 查詢作者"szq"的手機號,Author表 關聯(聯表) AuthorDetail表,一對一正向查詢
phone = Author.objects.filter(name='szq').values('authorDetail__phone')
print(phone) # <QuerySet [{'authorDetail__phone': 234567}]>
# QuerySet通過for循環拿到具體的值。
for n in phone:
print(n.get("authorDetail__phone"))
# 查詢手機號為"123456"對應的人的名字,AuthorDetail表 關聯(聯表) Author表,一對一反向查詢(按照表名小寫)
name = AuthorDetail.objects.filter(phone='123456').values('author__name')
print(name) # <QuerySet [{'author__name': 'sudada'}]>
return HttpResponse('ok')
2.6.2、一對多 正反向查詢
# 一對多 正反向查詢
def mui_query(request):
# 基於雙下劃線的跨表查詢,聯表查詢(一條SQL語句完成),正向查詢按照字段,反向查詢按照表名小寫
# 一對多的正向查詢,按照__另一個表的字段:'publish__city'
# 查詢"紅樓夢"這本書的出版社地址
city=Book.objects.filter(name="紅樓夢").values('publish__city')
print(city) # 拿到的數據都是一個個字典 <QuerySet [{'publish__city': '北京'}, {'publish__city': '北京'}, {'publish__city': '上海'}]>
# 一對多的反向查詢,
# 上海出版社出版的書籍有哪些
pub=Publish.objects.filter(name='北京出版社').values('book__name')
for book in pub:
'''
拿到的都是一個個字典
{'book__name': '水浒傳'}
{'book__name': '西游記'}
{'book__name': '三國'}
{'book__name': '紅樓夢'}
'''
print(book['book__name'])
return HttpResponse('ok')
2.6.3、多對多 正反向查詢
# 多對多 正反向查詢
def mui_query(request):
# 多對多的正向查詢
# 查詢"紅樓夢"這本書作者的名字
# 通過Book表找到'紅樓夢'這本書的id,然後通過中間表"Book_Author"找到id對應的作者author_id,再通過author_id找到作者的名字
res=Book.objects.filter(name='紅樓夢').values('authors__name') # <QuerySet [{'authors__name': 'sudada'}, {'authors__name': 'szq'}, {'authors__name': None}, {'authors__name': 'wsp'}]>
print(res)
# 多對多的反向查詢
# 查詢作者名為"szq"寫的所有書籍,Author表 -->Book表,多對多反向查詢
res=Author.objects.filter(name='szq').values('book__name')
print(res) # <QuerySet [{'book__name': '三國'}, {'book__name': '紅樓夢'}]>
return HttpResponse('ok')
2.7、多表的操作--連續跨表查詢
理解:在表A的基礎上,查詢到表B,然後查詢到表C並拿到表C的字段值(在表與表之間連續查詢時會用到正向與反向查詢)。values查詢的數據也是在表A的基礎上查詢到的(在表與表之間連續查詢時會用到正向與反向查詢)。
正向查詢:直接表字段
反向查詢:表名+字段
def mui_query(request):
# 需求:查詢手機號以33開頭的作者,出版過的書籍名稱及書籍出版社的名字
# 具體分析:可以通過以下4張表拿到想要的值
# 手機號:Authordetail
# 書名:Book
# 豎版社名稱:Publish
# 作者:Author
# 方法一:以AuthorDetail表為基准,查找到作者信息,那麼後面的values也是以AuthorDetail表為基礎查找"書籍名稱及書籍出版社的名字"
res=AuthorDetail.objects.filter(phone__startswith='33').values('author__book__name','author__book__publish__name')
# 在AuthorDetail表裡面,直接就可以通過匹配"phone"字段(正向查詢)。values後面的值是以AuthorDetail表為基礎,都是通過"反向查詢拿到的"
print(res) # <QuerySet [{'author__book__name': '紅樓夢', 'author__book__publish__name': '北京出版社'}]>
# 方法二:以Author表為基准,查找到作者信息,那麼後面的values也是以Author表為基礎查找"書籍名稱及書籍出版社的名字"
res=Author.objects.filter(authorDetail__phone__startswith='33').values('book__name','book__publish__name')
# 在Author表裡面,需要通過authorDetail表拿到phone字段(正向查詢)。values後面的值是以Author表為基礎,都是通過"反向查詢拿到的"
print(res) # <QuerySet [{'book__name': '紅樓夢', 'book__publish__name': '北京出版社'}]>
# 方法三:以Book表為基准,查找到作者信息,那麼後面的values也是以Book表為基礎查找"書籍名稱及書籍出版社的名字"
book=Book.objects.filter(authors__authorDetail__phone__startswith='33').values('name','publish__name')
# 在Book表裡面,需要通過authors表拿到authorDetail,然後拿到phone字段(正向查詢)。values後面的值是以Book表為基礎,都是通過"正向查詢拿到的"
print(book) # <QuerySet [{'name': '紅樓夢', 'publish__name': '北京出版社'}]>
# 方法四:以Publish表為基准,查找到作者信息,那麼後面的values也是以Publish表為基礎查找"書籍名稱及書籍出版社的名字"
pub=Publish.objects.filter(book__authors__authorDetail__phone__startswith='33').values('book__name','name')
# 在Publish表裡面,需要通過book表拿到authors表,然後通過authors表拿到authorDetail表,然後拿到phone字段(反向查詢)。values後面的值是以Publish表為基礎,其中'book__name'通過"反向查詢拿到的",'name'是通過"正向查詢拿到的"
print(pub) # <QuerySet [{'book__name': '紅樓夢', 'name': '北京出版社'}]>
return HttpResponse('ok')
2.8、聚合查詢 -- 使用 aggregate (聚合函數)
def mui_query(request):
# 聚合查詢 -- 使用aggregate:聚合函數
# 需求:查詢所有書籍的平均價格
# 需要先導入常用的功能,加.減.乘.除等等~
from django.db.models import Avg,Min,Max,Count
# 需求:查詢所有書籍的平均價格,書籍總數,書籍最高價與書籍最低價。
res = Book.objects.all().aggregate(Avg('price')) #書籍平均價格: {'price__avg': 221.375}
res = Book.objects.all().aggregate(Count('name')) #書籍總數: {'name__count': 8}
res = Book.objects.all().aggregate(Max('price')) #書籍最高價: {'price__max': Decimal('299.00')}
res = Book.objects.all().aggregate(Min('price')) #書籍最低價: {'price__min': Decimal('111.00')}
# 一行代碼實現:可以重命名
res = Book.objects.all().aggregate(Avg('price'),Count('name'),Max('price'),Min('price'))
print(res) # {'price__avg': 221.375, 'name__count': 8, 'price__max': Decimal('299.00'), 'price__min': Decimal('111.00')}
res = Book.objects.all().aggregate(pr=Avg('price'), co=Count('name'), ma=Max('price'), mi=Min('price'))
print(res) # {'pr': 221.375, 'co': 8, 'ma': Decimal('299.00'), 'mi': Decimal('111.00')}
return HttpResponse('ok')
2.9、F查詢與Q查詢
2.9.1、F查詢 (數據表內的2個值做比較時用到)
def mui_query(request):
# F查詢
# 需求:查詢"評論數"大於"閱讀數"的書籍
from django.db.models import F
book=Book.objects.filter(commit_num__gt=F('reat_num')).values('name')
print(book) # <QuerySet [{'name': '紅樓夢'}, {'name': '金瓶梅'}, {'name': '水浒傳'}, {'name': '紅寶書'}, {'name': '三國'}, {'name': '紅樓夢'}, {'name': '紅樓夢'}]>
# 需求:紅寶書價格加100
book = Book.objects.filter(name="紅寶書").update(price=F('price')+100)
print(book)
return HttpResponse('ok')
2.9.2、Q查詢,描述一個"與,或,非"的關系。 "|"表示或者,"&"表示且,"~"表示非
def mui_query(request):
# 需求:查詢名字為紅樓夢或者價格大於150的書籍
from django.db.models import Q
book=Book.objects.filter(Q(name="紅樓夢")|Q(price__gt=200))
print(book) # <QuerySet [<Book: 紅樓夢>, <Book: 金瓶梅>, <Book: 西游記>, <Book: 三國>, <Book: 紅樓夢>, <Book: 紅樓夢>]>
# 需求:查詢名字為紅樓夢且價格大於190的書籍
book = Book.objects.filter(Q(name="紅樓夢") & Q(price__gt=190))
print(book) # <QuerySet [<Book: 紅樓夢>]>
# Q查詢也可以Q套Q
# 需求:查詢名字為紅樓夢且價格大於190,或者nid大於2的書籍
book=Book.objects.filter((Q(name="紅樓夢") & Q(price__gt=190)) | Q(nid__gt=5))
print(book) # <QuerySet [<Book: 紅樓夢>, <Book: 三國>, <Book: 紅樓夢>, <Book: 紅樓夢>]>
# 需求:查詢名字不叫"紅樓夢"的書籍
book = Book.objects.filter(~Q(name="紅樓夢"))
print(book) # <QuerySet [<Book: 金瓶梅>, <Book: 水浒傳>, <Book: 紅寶書>, <Book: 西游記>, <Book: 三國>]>
return HttpResponse('ok')