● 外鍵的刪除操作---on_delete參數(shù)指定
<1> models.CASCADE---級聯(lián)刪除
外鍵表的字段被刪除后,原始表的整行數(shù)據(jù)也會被刪除
models
class Article(models.Model):
title=models.CharField(max_length=150)
content=models.TextField()
category=models.ForeignKey('Category',on_delete=models.CASCADE)
author=models.ForeignKey('front.FrontUser',on_delete=models.CASCADE,null=True)
article.views
def delete_view(request):
#category=Category.objects.first()
#category.delete() # 無需再調(diào)用category.save()
category=Category.objects.get(pk=2)
category.delete() # 外鍵表刪除后,原始表的整行數(shù)據(jù)也會被刪除
return HttpResponse('delete success!!!')
<2> models.PROTECT---保護
刪除外鍵的數(shù)據(jù)后,就會提示報錯保護,導致刪除操作無法被執(zhí)行
注意:此時外鍵的數(shù)據(jù)依然存在的,沒有被刪除
models
class Article(models.Model):
title=models.CharField(max_length=150)
content=models.TextField()
# 指定on_delete=models.PROTECT
category=models.ForeignKey('Category',on_delete=models.PROTECT)
author=models.ForeignKey('front.FrontUser',on_delete=models.CASCADE,null=True)
<3> models.SET_NULL---外鍵表的一行數(shù)據(jù)被刪除以后,原始表的關(guān)聯(lián)字段被替換成'null'
注意,原始表的數(shù)據(jù)依然存在(不會被刪除)
class Article(models.Model):
title=models.CharField(max_length=150)
content=models.TextField()
category=models.ForeignKey('Category',on_delete=models.SET_NULL,null=True)
author=models.ForeignKey('front.FrontUser',on_delete=models.CASCADE,null=True)
<4> models.SET_DEFAULT---外鍵表的一行數(shù)據(jù)被刪除以后,原始表的關(guān)聯(lián)字段被替換成
另外一個關(guān)鍵字參數(shù)default傳的值
class Article(models.Model):
title=models.CharField(max_length=150)
content=models.TextField()
# default=Category.objects.get(pk=5) 這么寫會報'序列化'錯誤,不清楚原因
category=models.ForeignKey('Category',
on_delete=models.SET_DEFAULT,null=True,default=5)
author=models.ForeignKey('front.FrontUser',on_delete=models.CASCADE,null=True)
<5> models.SET()---外鍵被刪除以后,原始表的關(guān)聯(lián)字段被替換成'set()傳的值'
注意,關(guān)聯(lián)字段該行的其他數(shù)據(jù)依然存在(不會被刪除)
from django.db import models
定義一個返回默認值的函數(shù)
def default_category():
return Category.objects.get(pk=5)
class Category(models.Model):
name=models.CharField(max_length=100)
class Article(models.Model):
title=models.CharField(max_length=150)
content=models.TextField()
# models.SET(5) 這么寫也可以
category=models.ForeignKey('Category',
on_delete=models.SET(default_category),null=True) # 注意這里的值是函數(shù)對象,而不是去調(diào)用函數(shù)方法
author=models.ForeignKey('front.FrontUser',on_delete=models.CASCADE,null=True)
class Comment(models.Model):
content=models.CharField(max_length=200)
orgin_comment=models.ForeignKey('self',on_delete=models.CASCADE)
● 表和表之間的關(guān)系,通過'外鍵'關(guān)聯(lián),那么,表和表之間的關(guān)系無非三種
'一對一','多對多','一對多(多對一)'
? 一對多(多對一)---通過ForeignKey屬性實現(xiàn)
示例:
article.models
from django.db import models
def default_category():
return Category.objects.get(pk=5)
class Category(models.Model):
name=models.CharField(max_length=100)
Article模型有4個字段,其中有兩個字段是外鍵
class Article(models.Model):
title=models.CharField(max_length=150)
content=models.TextField()
category=models.ForeignKey('Category',
on_delete=models.SET(default_category),null=True)
author=models.ForeignKey('front.FrontUser',on_delete=models.CASCADE,null=True)
article.views
def one_to_many_view(request):
# 先實例化一個對象
article=Article(title='A new day',content='Really really really')
# 獲取各自的字段
category=Category.objects.first() # category存儲的是Category模型的第一行所有數(shù)據(jù)
author=FrontUser.objects.first()
# 賦值并保存(注意保存)
article.category=category
article.author=author # author外鍵關(guān)聯(lián)外鍵表的一整行數(shù)據(jù),而不僅僅是其中的一個字段
article.save()
return HttpResponse('Successful!!!')
此時,若想獲取一個category目錄下面的所有'article'該怎么處理?
答案是利用動態(tài)生成的屬性---'article_set' # 或者利用'related_name'參數(shù)
article_set屬性類似objects,也有first(),all()等等方法,它返回的也是QuerySet對象
示例:
def one_to_many_view(request):
category=Category.objects.first()
article=category.article_set.all() # 也有這樣的方法: article_set.first()
for article in articles:
print(article) #<Article:雙英電影,Article:這是中英雙字幕的電腦> <Article:A new day,Article:Really really really>
return HttpResponse('Successful!!!')
注意,'article_set'這個動態(tài)屬性名稱是可以更改的,怎么改呢---'related_name'(也叫'反轉(zhuǎn)')
示例:
class Article(models.Model):
title=models.CharField(max_length=150)
content=models.TextField()
category=models.ForeignKey('Category',
on_delete=models.SET(default_category),related_name='articles',null=True) # 添加related_name參數(shù)
author=models.ForeignKey('front.FrontUser',on_delete=models.CASCADE,null=True)
def one_to_many_view(request):
category=Category.objects.first()
articles=category.articles.all() # 不再使用article_set屬性
for article in articles:
print(article)
return HttpResponse('Successful!!!')
? article.add()方法---分類下把文章添加進去
示例:
def one_to_many_view(request):
# 新增一條記錄,但category沒有賦值
article=Article(title='From now...',content='precious your time')
article.author=FrontUser.objects.first() # first()和get()的類型一樣,都是模型對象,區(qū)別于QuerySet對象
article.save()
# 獲取category并把文章添加進來
category = Category.objects.first()
category.articles.add(article) # 注意:在多對多關(guān)系中,add()會自動保存,無需再調(diào)用save()方法
category.save()
return HttpResponse('Successful!!!')
? article.add(bulk=False)---可以省略save()語句
示例:
def one_to_many_view(request):
article=Article(title='another test...',content='just just a ...')
article.author=FrontUser.objects.first()
category = Category.objects.first()
# bulk這個參數(shù),在'一對多'的關(guān)系中才有
category.articles.add(article,bulk=False)# 無需article.save(),category.save()
return HttpResponse('Successful!!!')
bulk源碼
def add(self, *objs, bulk=True): # 默認為True
......
if bulk:
......
else: # bulk=False
with transaction.atomic(using=db, savepoint=False):
for obj in objs:# 遍歷所有的對象,實現(xiàn)批量保存
check_and_update_obj(obj)
obj.save() # 執(zhí)行save()方法
add.alters_data = True
? 一對一關(guān)系---'models.OneToOneField':實質(zhì)也是外鍵
比如原始表定義:telephone=models.OneToOneField('TelephoneNumber',on_delete=models.CASCADE,null=True)
那就表明,'telephone'這個外鍵字段的'值'是不能重復的;但是...外鍵表的字段值不受約束,是可以重復的...
示例:
front.models
from django.db import models
class FrontUser(models.Model):
front_user=models.CharField(max_length=50)
后面添加的拓展類
class FrontUserExtension(models.Model):
school=models.CharField(max_length=100)
user=models.OneToOneField('FrontUser',on_delete=models.CASCADE)# 使用OneToOneField屬性
article.views
def one_to_one_view(request):
user=FrontUser.objects.first()
user_extension=FrontUserExtension(school='zhiliao')
user_extension.user=user
user_extension.save()
return HttpResponse('Successful!!!')
刷新一下數(shù)據(jù)庫,可以到效果,其實質(zhì)也是外鍵
此時若實例化另一個對象,依舊賦值user,那么就會報錯,因為是一對一關(guān)系
注意,上述示例如果修改一處,結(jié)論就變了
'''
def index(request):
author=Author.objects.last()
telephone=TelephoneNumber.objects.create(telephone=1234567891) # 這么寫,等于每次都重新建立一條數(shù)據(jù),所以不會報錯
author.telephone=telephone
author.save()
return HttpResponse('index')
'''
? 反向查詢---區(qū)別于'一對多'關(guān)系,沒有'model_set'這個屬性
而是直接'model'屬性
示例:
models
from django.db import models
class Student(models.Model):
name=models.CharField(max_length=100)
class School(models.Model):
grade=models.CharField(max_length=100)
user=models.OneToOneField('Student',on_delete=models.CASCADE)
views
通過外鍵表去查詢原始表的數(shù)據(jù)
def index3(request):
student=Student.objects.get(pk=3)
result=student.school.grade # 使用school屬性去訪問原始表字段,返回初三
print(result)
return HttpResponse('index3')
? 一對一的related_name用法
示例:
models
class FrontUserExtension(models.Model):
school=models.CharField(max_length=100)
# 添加related_name參數(shù)
user=models.OneToOneField('FrontUser',on_delete=models.CASCADE,related_name='userextension')
views
def one_to_one_view(request):
# extension=FrontUserExtension.objects.first()
# print(extension.user) # 直接關(guān)聯(lián)外鍵
user=FrontUser.objects.first()
print(user.userextension) # 外鍵的字段怎么轉(zhuǎn)回去?---related_name參數(shù)
return HttpResponse('Successful!!!')
review 示例:
models
class Student(models.Model):
name=models.CharField(max_length=100)
class School(models.Model):
grade=models.CharField(max_length=100)
user=models.OneToOneField('Student',on_delete=models.CASCADE,
related_name='shool_user')
views
def index3(request):
student=Student.objects.get(pk=3)
result=student.shool_user.grade # 通過school_user這個屬性去訪問原始表字段
print(result)
return HttpResponse('index3')
小結(jié):關(guān)于'一對一'和'一對多(多對一)'的反向查詢,最好指定'related_name'參數(shù)
避免造成混亂,也避免記憶
● 外鍵多對多關(guān)系
以'文章'和'標簽'示例,用來處理'多對多'關(guān)系的,實質(zhì)上是有3張表
'文章表','中間表'(定義兩個外鍵,來引用兩張表的主鍵),'標簽表'
示例:
models
class Tag(models.Model):
label=models.CharField(max_length=50) # 定義一個char字段
# 注意,這個屬性沒有 on_delete 參數(shù)
article=models.ManyToManyField('Article',related_name='tag') # 定義一個manytomany字段
class Article(models.Model):
title=models.CharField(max_length=150)
content=models.TextField()
category=models.ForeignKey('Category',
on_delete=models.SET(default_category),related_name='articles',null=True)
author=models.ForeignKey('front.FrontUser',on_delete=models.CASCADE,null=True)
def __str__(self):
message='<Article:{0},Article:{1}>'.format(self.title,self.content)
return message
遷移并寫入數(shù)據(jù)庫后,查看數(shù)據(jù)表
在'article_tag表中',有'id'和'label'列,查看這個表的外鍵,啥都沒?在哪呢...
答案就是'中間表---article_tag_article',表里有3個字段'id','tag_id','article_id'
其中,'tag_id'和'article_id'是外鍵,分別關(guān)聯(lián)兩張表的主鍵字段
views
def many_to_many_view(request):
article=Article.objects.first()
tag=Tag(label='熱門文章')
tag.save() # 記得保存
article.tag.add(tag) # 使用add()方法后,無需save()操作了
return HttpResponse('Successful...')
那么,是否可以參考之前的操作,使用bulk(一對多/多對一)參數(shù)呢?示例:
def many_to_many_view(request):
article=Article.objects.first()
tag=Tag(label='熱門文章')
###tag.save()
article.tag.add(tag,bulk=False) # 添加bulk參數(shù)
return HttpResponse('Successful...')
結(jié)果報錯了...### add() got an unexpected keyword argument 'bulk'
說明多對多關(guān)系,是沒有這個參數(shù)的.
我們再給一個標簽:
def many_to_many_view(request):
article=Article.objects.first()
tag=Tag(label='冷門文章')
tag.save()
article.tag.add(tag)
return HttpResponse('Successful...')
再次查看中間表,可以看到,一篇文章,確實可以有兩個label,那么,反過來呢?試試...
def many_to_many_view(request):
# 對于id=1的tag,插入兩條文章
tag=Tag.objects.get(pk=1)
#article=Article.objects.get(pk=4)
article=Article.objects.get(pk=5)
tag.article.add(article)
return HttpResponse('Successful...')
查看中間表,成功實現(xiàn)效果
獲取文章下面所有l(wèi)abel示例:
def many_to_many_view(request):
article=Article.objects.get(pk=3)
tags=article.tag.all()
for tag in tags:
print(tag)
return HttpResponse('Successful...')
小結(jié):外鍵不管定義的是哪種關(guān)系,'related_name'這個參數(shù)最好預先定義好,避免使用'ModelName_set'或者'ModelName'出現(xiàn)混亂
DB 查詢操作
<1>pycharm配置數(shù)據(jù)庫錯誤
[08001] Could not create connection to database server. Attempted reconnect 3 times. Giving up.
解決辦法:時區(qū)問題導致
將URL中內(nèi)容更改成如下形式:? 前面的'youdatabasename'替換成你自己的數(shù)據(jù)庫名稱
<2> 查詢的方法---'filter','exclude','get',三個方法,通過傳遞不同的參數(shù)來獲取查詢結(jié)果
參數(shù)的形式---field+'__'+condition # article=Article.objects.filter(title__contains='51cto')
下來,針對'condition'進行說明
A. exact(相當于'等于')
示例:
def index(request):
# 這里的'等于',不區(qū)分大小寫
#article=Article.objects.filter(title__exact='51CTO')
article=Article.objects.filter(title__exact='51cto') # 精確匹配,不區(qū)分大小寫(在Linux底下,就區(qū)分大小寫啦...)
print(article) # <QuerySet [<Article: <Model:Article,Title:51cto>>]>
print(article.query) # SELECT article
.id
, article
.title
, article
.content
FROM article
WHERE article
.title
= 51cto
return HttpResponse('data update successful!')
review示例
def index2(request):
articles=Article.objects.filter(title__exact='JS Article')
print(articles) # <QuerySet [<Article: Article object (2)>]>
print(articles[0].title) # JS Article 這種寫法也是可行的,而且執(zhí)行的SQL語句也會比較少,效率高
for article in articles:
print(article.title) # JS Article
return HttpResponse('index2')
注意:QuerySet對象既能支持遍歷,也可以使用'[索引]'的形式,去提取里面的對象
若值設置為None,則對應db的null
article=Article.objects.filter(title__exact=None)
SELECT article
.id
, article
.title
, article
.content
FROM article
WHERE article
.title
IS NULL
? iexact---windows系統(tǒng)幾乎與 exact 沒有區(qū)別,相當于db的'like'語句
示例:
def index(request):
article=Article.objects.filter(title__iexact='51CTO')
#article=Article.objects.filter(title__exact=None)
print(article) # <QuerySet [<Article: <Model:Article,Title:51cto>>]>
print(article.query) # SELECT article
.id
, article
.title
, article
.content
FROM article
WHERE article
.title
LIKE 51CTO
return HttpResponse('data update successful!')
注意:article.query這個屬性,必須是QuerySet對象才有的,若這里使用get()方法,返回的是模型對象,就沒有query這個屬性了
也就是說,無法獲取sql語句啦---<class 'front.models.Article'>
示例:
def index(request):
article=Article.objects.get(title__iexact='51CTO')
print(article)
print(article.query) # 'Article' object has no attribute 'query'
return HttpResponse('data update successful!')
B.contains---某個字段是否包含某個數(shù)據(jù)(大小寫敏感),模糊查找
示例:
def index(request):
article=Article.objects.filter(title__contains='51cto')
# 改成下面的形式,就找不到了,因為查詢條件是大寫
# article=Article.objects.filter(title__contains='CTO')
print(article) # <QuerySet [<Article: <Model:Article,Title:51cto>>]>
# 注意sql語句末尾的'%51cto%',前后的'%'表示任意字符,意味著這是一個模糊查找
print(article.query) # SELECT `article`.`id`, `article`.`title`, `article`.`content` FROM `article` WHERE `article`.`title` LIKE BINARY %51cto%
return HttpResponse('data update successful!')
? icontains---大小寫不敏感
示例:
def index(request):
article=Article.objects.filter(title__icontains='CTO')
print(article)# <QuerySet [<Article: <Model:Article,Title:51cto>>]>
print(article.query)# SELECT `article`.`id`, `article`.`title`, `article`.`content` FROM `article` WHERE `article`.`title` LIKE %CTO%
return HttpResponse('data update successful!')
● in---提取的field值是否在指定的容器中(可迭代對象,例如list,tuple,query_set對象)
示例:
def index(request):
articles=Article.objects.filter(id__in=[1,2,3]) # 這里使用id字段查詢,pycharm不會自動補齊(title,content字段會自動補齊)
for article in articles:
print(article) # 獲取了3條結(jié)果:<Model:Article,Title:51cto> <Model:A:oschina> <Model:Article,Title:hao123>
print(articles.query) # SELECT `article`.`id`, `article`.`title`, `article`.`contenrticle,Titlet` FROM `article` WHERE `article`.`id` IN (1, 2, 3)
return HttpResponse('data update successful!')
? 跨表的查詢操作
models
from django.db import models
class Categories(models.Model):
name=models.CharField(max_length=100)
def __str__(self):
message='<Model:Categories,Name:{}>'.format(self.name)
return message
class Article(models.Model):
title=models.CharField(max_length=100)
content=models.TextField()
category=models.ForeignKey('Categories',on_delete=models.CASCADE,
# 反向查詢參數(shù)
related_query_name='article',null=True)
# 模型對象查詢參數(shù)---related_name
# QuerySet對象查詢參數(shù)---related_query_name
class Meta:
db_table='article'
def __str__(self):
message='<Model:Article,Title:{}>'.format(self.title)
return message
現(xiàn)在往Categories模型插入一些數(shù)據(jù),然后在view操作:
from django.shortcuts import render
from django.http import HttpResponse
from .models import Article,Categories
def index(request):
# model__field__condition
# 獲取id為1,2,3的文章分類
# categories=Categories.objects.filter(article__id__in=[1,2,3]) 一樣的效果
categories=Categories.objects.filter(article__in=[1,2,3]) # 默認就是使用主鍵查詢
for category in categories:
print(category) # 獲取到3條數(shù)據(jù)
print(categories.query)
# SELECT `front_categories`.`id`, `front_categories`.`name` FROM `front_categories` INNER JOIN `article` ON (`front_categories`.`id` = `article`.`category_id`) WHERE `article`.`id` IN (1, 2, 3)
return HttpResponse('data update successful!')
review---比較'related_name'和'related_query_name'的區(qū)別,其實就是模型對象和'QuerySet對象'的區(qū)別
models
class Category(models.Model):
label=models.CharField(max_length=50)
class Article(models.Model):
title=models.CharField(max_length=50)
content=models.TextField()
author=models.ForeignKey('Author',on_delete=models.CASCADE,null=True)
category=models.ForeignKey('Category',on_delete=models.CASCADE,null=True,
related_name='article',related_query_name='query_article') # 分別設置兩個參數(shù)名稱
views
def index2(request):
categories=Category.objects.filter(query_article__in=[1,2,3])# QuerySet對象查詢條件使用
for category in categories:
print(category.label) # Hot Hot Ordinary
print('*'*40)
category1=Category.objects.first()# 獲取模型對象
articles=category1.article.all() # 模型對象使用
for article in articles:
print(article.title)
'''
How To Learn English
JS Article
Basketball
'''
return HttpResponse('index2')
可以看到,簡單的orm代碼,就可以實現(xiàn)復雜的sql語句操作
? 所有標題中包含xxx的分類示例1:
def index(request):
# 正向查詢
articles=Article.objects.filter(title__icontains='hao')
for article in articles:
print(article.category) # <Model:Categories,Name:最火>
return HttpResponse('data update successful!')
示例2---傳入QuerySet對象:
def index(request):
# 反向查詢
# 獲取分類---標題包含xx的分類
articles=Article.objects.filter(title__icontains='hao')
categories=Categories.objects.filter(article__id__in=articles) # 傳入QuerySet對象
for category in categories:
print(category)
return HttpResponse('data update successful!')
注意:查詢參數(shù)'article__in'包含非常多的查詢語句,在pycharm里面有很詳細的列出
? __gt(大于:greater),__gte(大于等于:greater equal),__lt(小于:lowter),__lte(小于等于:lowter equal)
示例:
def index(request):
# 查詢id>2的所有文章
articles=Article.objects.filter(id__gt=2)
for article in articles:
print(article) # <Model:Article,Title:hao123> <Model:Article,Title:360>
print(articles.query) # SELECT article
.id
, article
.title
, article
.content
, article
.category_id
FROM article
WHERE article
.id
> 2
return HttpResponse('data update successful!')
? startswith---字段的值以'xxx'開頭,大小寫敏感(istartswith:大小寫不敏感)
示例:
def index(request):
articles=Article.objects.filter(title__startswith=360)
for article in articles:
print(article) # <Model:Article,Title:360>
print(articles.query) # SELECT `article`.`id`, `article`.`title`, `article`.`content`, `article`.`category_id` FROM `article` WHERE `article`.`title` LIKE BINARY 360%
return HttpResponse('data update successful!')
注意sql語句末尾的'BINARY 360%'
endswith 用法類似,不再舉例
● __range:查詢某一個區(qū)間的值
示例:
models
class Article(models.Model):
title=models.CharField(max_length=100)
content=models.TextField()
category=models.ForeignKey('Categories',on_delete=models.CASCADE,
related_query_name='article',null=True)
create_time=models.DateTimeField(auto_now_add=True,null=True) # 添加時間字段
class Meta:
db_table='article'
def __str__(self):
message='<Model:Article,Title:{}>'.format(self.title)
return message
views
from django.shortcuts import render
from django.http import HttpResponse
from .models import Article,Categories
from datetime import datetime # 導入時間模塊
def index1(request):
# 獲取8:30-9:30之間發(fā)布的所有文章
start_time=datetime(year=2019,month=12,day=4,hour=8,minute=30,second=0)
end_time=datetime(year=2019,month=12,day=4,hour=9,minute=30,second=0)
articles=Article.objects.filter(create_time__range=(start_time,end_time)) # 示例用法
print(articles.query) # SELECT article
.id
, article
.title
, article
.content
, article
.category_id
, article
.create_time
FROM article
WHERE article
.create_time
BETWEEN 2019-12-04 00:30:00 AND 2019-12-04 01:30:00
for article in articles:
print(article) # 獲取了4條記錄
return HttpResponse('Successful!')
雖然成功返回想要的結(jié)果,但是django有一個紅色字體警告:
RuntimeWarning: DateTimeField Article.create_time received a naive datetime (2019-12-04 09:30:00) while time zone support is active.
RuntimeWarning)
我們之前說過,datetime獲取的是一個'naive time',這里如果想轉(zhuǎn)換成'aware time',需調(diào)用replace方法
但是,django提供另外的一個便捷的方法---make_aware()
示例:
from django.utils.timezone import make_aware # 這個模塊還有make_naive方法
def index1(request):
start_time=make_aware(datetime(year=2019,month=12,day=4,hour=8,minute=30,second=0))# 調(diào)用的方式也相當簡便
end_time=make_aware(datetime(year=2019,month=12,day=4,hour=9,minute=30,second=0))
articles=Article.objects.filter(create_time__range=(start_time,end_time))
print(articles.query)
for article in articles:
print(article)
return HttpResponse('Successful!')
查看 make_aware() 源碼,其實調(diào)用的也是replace方法:
def make_aware(value, timezone=None, is_dst=None):
"""Make a naive datetime.datetime in a given time zone aware."""
if timezone is None:
timezone = get_current_timezone()
if hasattr(timezone, 'localize'):
# This method is available for pytz time zones.
return timezone.localize(value, is_dst=is_dst)
else:
# Check that we won't overwrite the timezone of an aware datetime.
if is_aware(value):
raise ValueError(
"make_aware expects a naive datetime, got %s" % value)
# This may be wrong around DST changes!
return value.replace(tzinfo=timezone)
? __date查詢---使用的前提,需先配置mysql時區(qū)文件
示例:
def index1(request):
articles=Article.objects.filter(create_time__date=datetime(year=2019, # 使用__date查詢
month=12,day=4))
print(articles.query)
for article in articles:
print(article)
return HttpResponse('Successful!')
返回的結(jié)果為空...查看SQL語句:
SELECT article
.id
, article
.title
, article
.content
, article
.category_id
, article
.create_time
FROM article
WHERE DATE(CONVERT_TZ(article
.create_time
, 'UTC', 'Asia/Shanghai')) = 2019-12-04
其中,'UTC','Asia/Shanghai'是SQL數(shù)據(jù)庫不能識別的時區(qū),怎么破?我們需要配制mysql的時區(qū)文件
下載地址:https://dev.mysql.com/downloads/timezones.html # timezone_2019c_posix_sql.zip - POSIX standard
替換以下路徑的sql時區(qū)文件('''請先做好備份,以防萬一''')
C:\ProgramData\MySQL\MySQL Server 5.5\data\mysql
然后重啟mysql服務
不更改django任何代碼,現(xiàn)在重新刷新網(wǎng)頁,可以看到,查詢到了我們想要的結(jié)果:
SELECT article
.id
, article
.title
, article
.content
, article
.category_id
, article
.create_time
FROM article
WHERE DATE(CONVERT_TZ(article
.create_time
, 'UTC', 'Asia/Shanghai')) = 2019-12-04
<Model:Article,Title:51cto>
<Model:Article,Title:oschina>
<Model:Article,Title:hao123>
<Model:Article,Title:360>
? __year查詢:查詢年份
示例:
def index1(request):
articles=Article.objects.filter(create_time__year=2019) # SELECT `article`.`id`, `article`.`title`, `article`.`content`, `article`.`category_id`, `article`.`create_time` FROM `article` WHERE `article`.`create_time` BETWEEN 2018-12-31 16:00:00 AND 2019-12-31 15:59:59
print(articles.query)
for article in articles:
print(article) # 獲取到了4條記錄
return HttpResponse('Successful!')
延伸示例 __year__gte:
def index1(request):
articles=Article.objects.filter(create_time__year__gte=2018) # 獲取大于等于2018年份的數(shù)據(jù)
print(articles.query)
for article in articles:
print(article)
return HttpResponse('Successful!')
'''SELECT article
.id
, article
.title
, article
.content
, article
.category_id
, article
.create_time
FROM article
WHERE article
.create_time
>= 2017-12-31 16:00:00
[04/Dec/2019 09:40:39] "GET / HTTP/1.1" 200 11
<Model:Article,Title:51cto>
<Model:Article,Title:oschina>
<Model:Article,Title:hao123>
<Model:Article,Title:360>'''
? __day的用法和 __year 類似
示例:
只要是4號,不管是哪一個月份,都會返回結(jié)果
def index1(request):
articles=Article.objects.filter(create_time__day=4) # 成功獲取
print(articles.query)
for article in articles:
print(article)
return HttpResponse('Successful!')
? week_day:表示星期幾,周日是1,周一到六是從:2-7
示例:
def index1(request):
articles=Article.objects.filter(create_time__week_day=4) # 獲取周三發(fā)布的article數(shù)據(jù)
print(articles.query)
for article in articles:
print(article)
return HttpResponse('Successful!')
? __time:根據(jù)時間查詢,傳入的time對象必須精確到秒,所以用區(qū)間(range)查詢比較穩(wěn)妥
其實精確到秒查詢也是可以的,實戰(zhàn)中很少會這么處理,一般都是用區(qū)間
示例:
def index1(request):
start_time=time(hour=8,minute=38,second=0)
end_time=time(hour=8,minute=38,second=59)
articles=Article.objects.filter(create_time__time__range=(start_time,end_time)) # 1分鐘內(nèi)的區(qū)間去獲取結(jié)果
print(articles.query)
for article in articles:
print(article)
return HttpResponse('Successful!')
'''
SELECT article
.id
, article
.title
, article
.content
, article
.category_id
, article
.create_time
FROM article
WHERE TIME(CONVERT_TZ(article
.create_time
, 'UTC', 'Asia/Shanghai')) BETWEEN 08:38:00 AND 08:38:59
<Model:Article,Title:51cto>
<Model:Article,Title:oschina>
<Model:Article,Title:hao123>
<Model:Article,Title:360>
'''
? __isnull---判斷某個字段是否為空
def index1(request):
articles=Article.objects.filter(create_time__isnull=True) # 獲取到了一條結(jié)果,若這里為False獲取到就是不為空的字段了
print(articles.query)
for article in articles:
print(article)
return HttpResponse('Successful!')
'''
SELECT article
.id
, article
.title
, article
.content
, article
.category_id
, article
.create_time
FROM article
WHERE article
.create_time
IS NULL
<Model:Article,Title:新浪>
'''
? __regex---正則查詢,區(qū)分大小寫(__iregex 不區(qū)分大小寫)
使用這個參數(shù),可以匹配出復雜的正則表達式.
示例:
def index1(request):
articles=Article.objects.filter(title__regex=r'^os') # 獲取以os開頭的title字段
print(articles.query)
for article in articles:
print(article)
return HttpResponse('Successful!')
'''
SELECT article
.id
, article
.title
, article
.content
, article
.category_id
, article
.create_time
FROM article
WHERE article
.title
REGEXP BINARY ^os
<Model:Article,Title:oschina>
'''
我們之前對字段是做了一些'查詢'的操作,現(xiàn)在,我們對字段做'計算'操作
● 聚合函數(shù)(例如Avg,Count)的調(diào)用---aggregate():提取數(shù)據(jù)的一種方法
比如提取某個商品銷售的數(shù)量,那么可以使用Count;如果想要知道商品銷售的平均價格,那么可以使用Avg
聚合函數(shù)Count,Avg是不能直接調(diào)用了,得通過aggregate()方法調(diào)用
這個方法返回一個字典---例如使用'avg',默認'field_avg'的樣式
'''
如果你用原生SQL,則可以使用聚合函數(shù)來提取數(shù)據(jù)。比如提取某個商品銷售的數(shù)量,那么可以使用Count,
如果想要知道商品銷售的平均價格,那么可以使用Avg。
聚合函數(shù)是通過aggregate方法來實現(xiàn)的,aggregate翻譯就是'聚合',表示所有
'''
示例:
models
from django.db import models
class Author(models.Model):
name=models.CharField(max_length=100)
age=models.IntegerField()
email=models.EmailField()
class Meta:
db_table='author'
class Publisher(models.Model):
name=models.CharField(max_length=300)
class Meta:
db_table='publisher'
class Book(models.Model):
name=models.CharField(max_length=300)
pages=models.IntegerField()
price=models.FloatField()
rating=models.FloatField()
author=models.ForeignKey('Author',on_delete=models.CASCADE)
publisher=models.ForeignKey('Publisher',on_delete=models.CASCADE)
class Meta:
db_table='book'
class BookOrder(models.Model):
book=models.ForeignKey('Book',on_delete=models.CASCADE)
price=models.FloatField()
class Meta:
db_table='book_order'
views
from django.shortcuts import render
from .models import *
from django.http import HttpResponse
from django.db.models import Avg
def index(request):
result=Book.objects.aggregate(Avg('price')) # 這里的Avg('price')實質(zhì)就是執(zhí)行原生的SQL語句,所以可以這么寫
print(result) # {'price__avg': 106.69999999999999}
return HttpResponse('Successful!')
注意: price__avg 結(jié)構(gòu)是根據(jù) field__avg 規(guī)則構(gòu)成的如果想要修改默認的名字,那么可以將Avg賦值給一個關(guān)鍵字參數(shù)。示例代碼如下:
views
def index(request):
result=Book.objects.aggregate(my_avg=Avg('price'))
print(result) # {'my_avg': 106.69999999999999}
return HttpResponse('Successful!')
注意,此時若想查詢sql語句,使用以下代碼是錯誤的:
print(result.query) # 因為result不是QuerySet對象
若想看SQL語句,可以這么處理:
from django.shortcuts import render
from .models import *
from django.http import HttpResponse
from django.db.models import Avg
from django.db import connection # 導入connection
def index(request):
result=Book.objects.aggregate(my_avg=Avg('price'))
print(result)
print(connection.queries) # 使用queries屬性來獲取SQL語句
return HttpResponse('Successful!')
結(jié)果:
{'my_avg': 106.69999999999999}
[{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'}, {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'}, {'sql': 'SELECT AVG(book
.price
) AS my_avg
FROM book
', 'time': '0.001'}] # 列表里面的字典,最后一句就是執(zhí)行的SQL語句
現(xiàn)在有一個這樣的需求,獲取每一本書銷售的平均價格,是否這樣處理:
from django.shortcuts import render
from .models import *
from django.http import HttpResponse
from django.db.models import Avg
from django.db import connection
def index(request):
# 獲取每一本書銷售的平均價格
# avg_result=Book.objects.aggregate(Avg('bookorder.price')) # 這種寫法是錯誤的
result=Book.objects.aggregate(Avg('bookorder__price'))# 查詢里面,使用雙下劃線的形式,而不是'.'號形式
print(result) # {'bookorder__price__avg': 96.66666666666667}
print(connection.queries)
'''
[{'time': '0.001', 'sql': 'SELECT @@SQL_AUTO_IS_NULL'}, {'time': '0.000', 'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED'}, {'time': '0.026', 'sql': 'SELECT AVG(book_order
.price
) AS bookorder__price__avg
FROM book
LEFT OUTER JOIN book_order
ON (book
.id
= book_order
.book_id
)'}]
'''
return HttpResponse('Successful!')
結(jié)果發(fā)現(xiàn),這段代碼的處理結(jié)果(查看SQL語句),是獲取了所有圖書銷售價格的平均值,這顯然不是我們想要的
A. aggregate---表示聚合,統(tǒng)計字段的所有值,調(diào)用計算函數(shù)處理,例如Count,Avg,Sum等等#獲取字段的所有數(shù)據(jù),并用聚合函數(shù)處理
B. annotate(注釋)---為每一個字段添加一個新的屬性,在這個屬性里,可以進行計算函數(shù)處理#每行數(shù)據(jù)添加字段,分組(group by),然后聚合函數(shù)處理
示例:
from django.shortcuts import render
from .models import *
from django.http import HttpResponse
from django.db.models import Avg
from django.db import connection
def index(request):
# 獲取每一本書銷售的平均價格
# resulets是一個QuerySet對象
results=Book.objects.annotate(avg=Avg('bookorder__price'))
for result in results:
# result.avg屬性是在results生成的
print('{0},{1}'.format(result.name,result.avg))
print(connection.queries)
return HttpResponse('Successful!')
'''
十萬個為什么,130.0
生活知識百科,63.333333333333336
戰(zhàn)爭知識百科全書,None
天氣預報常識,None
[{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'}, {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'}, {'sql': 'SELECT book
.id
, book
.name
, book
.pages
, book
.price
, book
.rating
, book
.author_id
, book
.publisher_id
, AVG(book_order
.price
) AS avg
FROM book
LEFT OUTER JOIN book_order
ON (book
.id
= book_order
.book_id
) GROUP BY book
.id
ORDER BY NULL', 'time': '0.000'}]
'''
結(jié)果符合預期
注意,annotate這個方法,最好在跨表操作的時候應用
比如以下單表操作,結(jié)果不是預期的:
def index3(request):
# 給bookorder每一個對象添加一個屬性,這個屬性的作用是---統(tǒng)計price的平均值
results=BookOrder.objects.annotate(my_avg=Avg('price'))
for result in results:
print(result.id,':',result.my_avg)
print(connection.queries)
return HttpResponse('index3')
'''
1 : 220.0
2 : 215.0
3 : 230.0
4 : 180.0
5 : 205.0
6 : 220.0
7 : 222.0
[{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'}, {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'}, {'sql': 'SELECT book_order
.id
, book_order
.book_id
, book_order
.price
, AVG(book_order
.price
) AS my_avg
FROM book_order
GROUP BY book_order
.id
ORDER BY NULL', 'time': '0.001'}]
'''