模型元選項(xiàng)
- 每個(gè)model都可以定義一個(gè)Meta類,使用內(nèi)部的class Meta 定義模型的元數(shù)據(jù),這個(gè)類中可以定義一些關(guān)于你的配置,Meta是一個(gè)model內(nèi)部的類
- 模型元數(shù)據(jù)是“任何不是字段的數(shù)據(jù)”,比如排序選項(xiàng)(ordering),數(shù)據(jù)庫(kù)表名(db_table)或者人類可讀的單復(fù)數(shù)名稱(verbose_name 和verbose_name_plural)。在模型中添加class Meta是完全可選的,所有選項(xiàng)都不是必須的。
class Meta:
db_table = "topic"
managed = True
ordering = ['-id']
verbose_name = u"主題"
verbose_name_plural = u"主題列表"
db_table:string,在數(shù)據(jù)庫(kù)中的表名,否則Django自動(dòng)生成為app名字_類名
managed: bool, 默認(rèn)值為T(mén)rue,這意味著Django可以使用syncdb和reset命令來(lái)創(chuàng)建或移除對(duì)應(yīng)的數(shù)據(jù)庫(kù)。
ordering: 數(shù)組, 默認(rèn)排序規(guī)則,每個(gè)字符串是一個(gè)字段名,前面帶有可選的“-”前綴表示倒序。前面沒(méi)有“-”的字段表示正序。使用"?"來(lái)表示隨機(jī)排序。
verbose_name: string model對(duì)象的描述
verbose_name_plural: string 復(fù)數(shù)時(shí)的描述
模型字段
image.png

模型字段常用的參數(shù)
image.png

null與blank:
- blank 是針對(duì)表單的,如果 blank=True,表示你的表單填寫(xiě)該字段的時(shí)候可以不填,比如 admin 界面下增加 model 一條記錄的時(shí)候。直觀的看到就是該字段不是粗體,設(shè)置為False時(shí),字段是必須填寫(xiě)的。字符型字段CharField和TextField是用空字符串來(lái)存儲(chǔ)空值的。默認(rèn)不允許為空。
- null 是針對(duì)數(shù)據(jù)庫(kù)而言,如果 null=True, 表示數(shù)據(jù)庫(kù)的該字段可以為空。默認(rèn)不允許。日期型、時(shí)間型和數(shù)字型字段不接受空字符串。所以設(shè)置IntegerField,DateTimeField型字段可以為空時(shí),需要將blank,null均設(shè)為T(mén)rue。
總之:
blank,只是在form表單驗(yàn)證時(shí)可以為空,而在數(shù)據(jù)庫(kù)上存儲(chǔ)的是一個(gè)空字符串;null是在數(shù)據(jù)庫(kù)上表現(xiàn)NULL,而不是一個(gè)空字符串;
需要注意的是,日期型(DateField、TimeField、DateTimeField)和數(shù)字型(IntegerField、DecimalField、FloatField)不能接受空字符串,如要想要在填寫(xiě)表單的時(shí)候這兩種類型的字段為空的話,則需要同時(shí)設(shè)置null=True、blank=True;
auto_now 與auto_now_add區(qū)別:
auto_now_add: 只有第一次才會(huì)生效,比如可以用于文章創(chuàng)建時(shí)間
auto_now: 每一次修改保存對(duì)象時(shí)都會(huì)將當(dāng)前時(shí)間更新進(jìn)去,只有調(diào)用Model.save()時(shí)更新,在以其他方式(例如 QuerySet.update())更新其他字段時(shí),不會(huì)更新該字段,但您可以在此類更新中為字段指定自定義值??捎糜谖恼滦薷臅r(shí)間;
模型中的關(guān)系
一對(duì)一:一本書(shū)籍有一個(gè)編號(hào);
多對(duì)一:一本書(shū)籍有多個(gè)評(píng)論;--注意Django只有多對(duì)一關(guān)系,站在多的角度去看待;
多對(duì)多:一本書(shū)籍有多個(gè)作者,一個(gè)作者可以寫(xiě)多本書(shū)籍;
class Author(models.Model):
name = models.CharField(u'姓名', max_length=200)
email = models.EmailField(u'郵箱')
class Number(models.Model):
number = models.CharField(u'編號(hào)', max_length=200)
class Book(models.Model):
headline = models.CharField(u'大標(biāo)題', max_length=255)
pub_date = models.DateTimeField(u'出版時(shí)間')
authors = models.ManyToManyField(Author)
number = models.OneToOneField(Number)
class Reply(models.Model):
book = models.ForeignKey(Book) #外鍵字段
content = models.CharField(u'內(nèi)容', max_length=255)
- ForeignKey外鍵
多對(duì)一關(guān)系,關(guān)聯(lián)模型關(guān)聯(lián)的類,定義在多的類中,如上Reply類中;
屬性:
db_constraint:bool 是否建立外鍵約束
to_field:string 關(guān)聯(lián)到的關(guān)聯(lián)對(duì)象的字段名稱。默認(rèn)地,Django 使用關(guān)聯(lián)對(duì)象的主鍵。
related_name: string 關(guān)聯(lián)對(duì)象反向引用描述符。.如果你不想讓Django 自動(dòng)創(chuàng)建一個(gè)反向關(guān)聯(lián)(Django自動(dòng)是以子表_set命名的),則可以自己定義。
on_delete: string 可以取如下值
CASCADE:級(jí)聯(lián)刪除,如果刪除,相關(guān)聯(lián)的那個(gè)也會(huì)刪除
PROTECT:保護(hù)類型。如果刪除,將會(huì)拋出一個(gè)ProtectedError錯(cuò)誤
SET_NULL:如果刪除了本條數(shù)據(jù),外鍵的那條數(shù)據(jù)將會(huì)設(shè)置為null,這個(gè)只有在外鍵null為T(mén)rue的情況下才可以使用
SET_DEFAULT:如果刪除了本條數(shù)據(jù),外鍵那條數(shù)據(jù)將會(huì)職位默認(rèn)值,這個(gè)只有在外鍵那個(gè)字段設(shè)置了default參數(shù)才可以使用 - ManyToManyField
多對(duì)多關(guān)系,定義在哪個(gè)類中都可以,如上Book類中;
屬性:
related_name: string 與ForeignKey相同
db_table:string 需要建立關(guān)聯(lián)表的表名
db_constraint: 同上 - OneToOneField
一對(duì)一關(guān)系,定義在哪個(gè)類中都可以,如書(shū)籍和編號(hào);
屬性:
on_delete 同F(xiàn)oreignKey
to_field 同F(xiàn)oreignKey
持久操作
Model.save()
這個(gè)方法可以用來(lái)插入一條新的數(shù)據(jù),也可以用來(lái)更新一條數(shù)據(jù)。如果這個(gè)數(shù)據(jù)在之前數(shù)據(jù)庫(kù)中存在了,就只是調(diào)用sql的update語(yǔ)句。如果這條數(shù)據(jù)是新的,就會(huì)調(diào)用sql的insert語(yǔ)句。示例代碼如下:
class UpdateArticle(View):
def get(self,request):
# 批量修改
# UPDATE hello_article SET status=3 WHERE status=2
# Article.objects.filter(status=2).update(status=3)
# 單個(gè)修改
# 實(shí)際上save方法如果當(dāng)前實(shí)例已經(jīng)存在于數(shù)據(jù)庫(kù)中,它就會(huì)當(dāng)作一個(gè)update操作
# Article.objects.filter(id=7).update(status=4)
article = Article.objects.get(pk=8) #取出pk=7的對(duì)象,然后修改其狀態(tài),再保存
article.status = 0
article.save()
#更新之后在查詢
articleAll = Article.objects.all()
return render(request, 'displayArticle.html', locals())
注意:save操作不止是更新修改的字段,而是會(huì)將所有的字段全部更新一遍,不管有沒(méi)有修改。當(dāng)你的所有操作都是串行,沒(méi)有什么并發(fā)同時(shí)操作同一個(gè)model的時(shí)候,這樣的處理方式,一般不會(huì)給你帶來(lái)任何麻煩。但是并行的時(shí)候可能會(huì)有影響。
Django后面在save方法里面新增加了一個(gè)update_fields參數(shù)。這樣就可以只修改特定字段了:
user.name = name
user.save(update_fields=['name'])
這樣便有效避免了并行save產(chǎn)生的數(shù)據(jù)沖突。
檢索對(duì)象
- get(**kwargs)方法:查詢單個(gè)數(shù)據(jù),只會(huì)返回一個(gè)對(duì)象,如果所有條件都不滿足或者是滿足條件的有多個(gè),將拋出一個(gè)異常。
article = Article.objects.get(pk=1) #在django 的ORM查詢中,數(shù)據(jù)庫(kù)的主鍵可以用PK代替, 官方推薦使用pk
article = Article.objects.get(id=1)#等同于select * from hello_article where id=1;
- all() 獲取所有
articleAll = Article.objects.all()
- filter(**kwargs)方法:根據(jù)參數(shù)提供的提取條件,獲取一個(gè)過(guò)濾后的QuerySet。
Article.objects.filter(status = 0)
- exclude(**kwargs)方法:根據(jù)參數(shù)提供的條件,排除符合條件的數(shù)據(jù),返回一個(gè)QuerySet對(duì)象。
Article.objects.exclude(status = 0)
- order_by(*args):根據(jù)給定的參數(shù)進(jìn)行排序.
#正序:
Book .objects.filter(headline=u'標(biāo)題').order_by('pub_date')
#倒序,字段前面加-
Book .objects.filter(headline=u'標(biāo)題').order_by('-pub_date')
- values()方法:將返回來(lái)的QuerySet中的Model轉(zhuǎn)換為字典
#<QuerySet [<Classesgrade: Classesgrade object>, <Classesgrade: Classesgrade object>]>
cgrade = Classesgrade.objects.all()
#<QuerySet [{'update_time': datetime.datetime(2018, 4, 7, 4, 44, 56, 181307,
cninfo=<UTC>), 'create_time': datetime.datetime(2018, 4, 7, 4, 44, 56, 181269,
cninfo=<UTC>), u'number_id': 1L, u'id': 1L, 'name': u'django\u6846\u67b6\u73ed'},
{'update_time': datetime.datetime(2018, 4, 7, 4, 44, 56, 405850, cninfo=<UTC>),
'create_time': datetime.datetime(2018, 4, 7, 4, 44, 56, 405816, cninfo=<UTC>),
u'number_id': 2L, u'id': 2L, 'name': u'django\u6846\u67b6\u73ed'}]>
cgrade.values()
- count()方法:將返回當(dāng)前查詢到的數(shù)據(jù)的總數(shù),這個(gè)比length方法更有效
Book .objects.count()
- latest(field_name=None)方法:根據(jù)提供的參數(shù)field_name來(lái)進(jìn)行排序,field_name這個(gè)參數(shù)必須是時(shí)間字段,然后提取離現(xiàn)在最近的一條數(shù)據(jù)
Book .objects.latest('pub_date')
- earliest()方法:用法和latest一樣,只是這個(gè)是獲取最久遠(yuǎn)的一個(gè)。
Book .objects.latest('pub_date')
- first()方法:獲取查詢到的數(shù)據(jù)的第一條數(shù)據(jù)。如果用了order_by,那么將獲取排序后的第一條。如果沒(méi)有用order_by,那么將根據(jù)id進(jìn)行默認(rèn)排序。
Book .objects.first()
- last()方法:用法和first一樣,只不過(guò)是獲取的是最后一條的數(shù)據(jù)。
Book .objects.last()
- update(**kwargs):更新數(shù)據(jù)方法,這個(gè)方法可以對(duì)查詢出來(lái)的QuerySet里面的所有元素進(jìn)行更新,并且更新參數(shù)的個(gè)數(shù)也是不限的。另外要注意的是,因?yàn)間et方法返回的不是QuerySet對(duì)象,因此使用get方法提取出來(lái)的數(shù)據(jù)不能使用update方法。出于這種情況,建議應(yīng)該使用filter(pk=xx)來(lái)替代get(pk=xxx)方法。并且,使用get出來(lái)的模型,修改數(shù)據(jù)后再save,會(huì)更新所有的數(shù)據(jù),比update的效率更低。
Book .objects.filter(id=1).update(headline="大標(biāo)題")
- delete()方法:刪除QuerySet中的模型。
Book .objects.filter(id=1).delete()
查找對(duì)象的條件
查找對(duì)象的條件的意思是傳給以上方法的一些參數(shù)。比如name__contains=’abc’這個(gè)就代表name這個(gè)字段包含了abc的意思,相當(dāng)于是SQL語(yǔ)句中的where語(yǔ)句后面的條件,語(yǔ)法為字段名__規(guī)則,以下將對(duì)這些規(guī)則進(jìn)行說(shuō)明:
- exact:相當(dāng)于等于號(hào)
Book .objects.filter(headline__exact=u'大標(biāo)題')
或
Book .objects.filter(headline=u'大標(biāo)題')
- iexact:跟exact,只是忽略大小寫(xiě)的匹配。
Book .objects.filter(headline__iexact=u'大標(biāo)題')
- contains:字符數(shù)據(jù)中包含等號(hào)后面的數(shù)據(jù)。
Book .objects.filter(headline__contains=u'標(biāo)題')
- icontains:跟contains,唯一不同是忽略大小寫(xiě)。
Book .objects.filter(headline__icontains=u'標(biāo)題')
- in:判斷字符的數(shù)據(jù)是否處在一個(gè)給定的列表中,如果在,則提取出來(lái)。
Book .objects.filter(id__in=[1, 2, 3])
- gt:大于。
Book .objects.filter(id__gt=1)
- gte:大于等于。
Book .objects.filter(id__gte=1)
- lt:小于。
Book .objects.filter(id__lt=10)
- lte:小于等于。
Book.objects.filter(id__lte=10)
- startswith:以什么開(kāi)始。
Book .objects.filter(headline__startswith='title')
- istartswith:同startswith,忽略大小寫(xiě)。
Book .objects.filter(headline__istartswith='title')
- endswith:同startswith,以什么結(jié)尾。
Book .objects.filter(headline__iendswith='le')
- iendswith:同istartswith,以什么結(jié)尾忽略大小寫(xiě)。
Book .objects.filter(headline__iendswith='le')
- range:區(qū)間查詢。
import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2018, 1, 1)
Book .objects.filter(pub_date__range=(start_date, end_date))
- isnull:判斷是否是空。
Book .objects.filter(pub_date__isnull=True) zz ..,. MJ HM
- 切片:對(duì)查找出來(lái)的數(shù)據(jù)進(jìn)行切片,跟用數(shù)組是一樣的。
Book.objects.all()[:2]
*ps:負(fù)值的操作,是無(wú)法進(jìn)行。切片可以用來(lái)實(shí)現(xiàn)翻頁(yè)顯示內(nèi)容,比如每一頁(yè)顯示10條內(nèi)容可以利用切片,第page頁(yè)
cnumber = Classesnumber.objects.all() #獲取Classesnumber的Queryset集
cn_counts = cnumber.count() #總記錄數(shù)
page_count = 4 #每頁(yè)顯示記錄
#求出分多少頁(yè)
for page in range((cn_counts / page_count + cn_counts % page_count)):
#利用for遍歷出每一頁(yè)的記錄數(shù)據(jù)
for pagenum in (cnumber[page*page_count:page*page_count + page_count]):
print(pagenum.classgrade_number)
外鍵操作
一對(duì)一
- 訪問(wèn)
在建立關(guān)聯(lián)屬性的類里面直接.關(guān)聯(lián)屬性即可
book = Book.objects.get(pk=1) #先獲取從表的對(duì)象,Book為從表
book.number #得到book主鍵為1的對(duì)應(yīng)Number對(duì)象主表
- 增加
book = Book.objects.get(pk=1)
book.number = number #獲取Number主類的對(duì)象,再賦給book中的關(guān)聯(lián)屬性
book.save() #再save保存
- 反查
number = Number.objects.get(pk=1) #Number為主類,Book為從類
number.book #查詢編號(hào)對(duì)應(yīng)的書(shū)籍
多對(duì)一
- 訪問(wèn)
訪問(wèn)外鍵:Reply(多)的對(duì)象要訪問(wèn)他所持有的book(一)對(duì)象
reply = Reply.objects.get(pk=1) #先獲取多類(子表)對(duì)象
reply.book # 字表
反查(一查多,主查從)
外鍵反向訪問(wèn):如果Book對(duì)象想要訪問(wèn)所有引用了他的Reply對(duì)象,因?yàn)闆](méi)有外鍵屬性,不能采用“.”方式訪問(wèn),可以通過(guò)“模型名_set“進(jìn)行訪問(wèn)。如果模型I有一個(gè)ForeignKey,那么該ForeignKey 所指的模型II實(shí)例可以通過(guò)一個(gè)管理器回前面有ForeignKey的模型I的所有實(shí)例。默認(rèn)情況下,這個(gè)管理器的名字為foo_set,其中foo 是源模型的小寫(xiě)名稱。默認(rèn)是以
子表小寫(xiě)名稱_set()來(lái)表示(上面默認(rèn)以b_set訪問(wèn)),
可以在從表定義時(shí)設(shè)置related_name 參數(shù)來(lái)覆蓋foo_set 的名稱。通過(guò)主表來(lái)查詢子表信息用到反向查詢(返回的是管理器,需要all之類返回QuerySet),
# 本身Number對(duì)象是沒(méi)有book屬性,django提供的一個(gè)反查機(jī)制
# 如果設(shè)置related_name, 我們就通過(guò)related_name反查
# 如果沒(méi)有設(shè)置, django默認(rèn)設(shè)置的是反查class的小寫(xiě)名字
# related_name 可以當(dāng)成反查所用的別名
book = Book.objects.get(pk=1)
book.reply_set.all()
#還可以進(jìn)行查詢
book = Book.objects.get(pk=1)
book.reply_set.filter(content__contains=’I love’).all()
- 添加
# 多對(duì)一創(chuàng)建的對(duì)象,它是默認(rèn)沒(méi)有加載外鍵的,只有當(dāng)你引用時(shí),它才會(huì)加載
reply = Reply.objects.get(pk=1) #首先主表要有數(shù)據(jù),從表才能與之相對(duì)應(yīng)
reply.book = book #book是從主類獲取的對(duì)象,此處省略
reply.save() #再保存
# 反向操作
多對(duì)多
- 訪問(wèn)
多對(duì)多訪問(wèn):跟外鍵訪問(wèn)一樣,“模型名_set“進(jìn)行反向訪問(wèn)。
Book .authors 等于同Book .objects.filter(reply_id=Reply.id).all()
book = Book.objects.get(pk=1)
book.authors
反查
“模型名_set“進(jìn)行反向訪問(wèn)。與多對(duì)一類似添加
多對(duì)多數(shù)據(jù)添加需要先保存子表對(duì)象,然后再add進(jìn)行添加主類對(duì)象
book = Book(headline="標(biāo)題",number=number)
book.save()
book.authors.add(author)
book.authors.add(author1)
book.save()
- 刪除
book.authors.remove(author)
book.save()
處理關(guān)聯(lián)對(duì)象方法
add(obj1, obj2, ...) 添加的已經(jīng)存在數(shù)據(jù)庫(kù)的數(shù)據(jù)
添加一指定的模型對(duì)象到關(guān)聯(lián)的對(duì)象集中。
d = Department.objects.get(pk=1)
s = Student.objects.get(pk=1)
d.student_set.add(s) # 學(xué)院d添加學(xué)生s
create(**kwargs) 添加不存在的數(shù)據(jù) ,將數(shù)據(jù)直接存入數(shù)據(jù)庫(kù)
創(chuàng)建一個(gè)新的對(duì)象,將它保存并放在關(guān)聯(lián)的對(duì)象集返回新創(chuàng)建的對(duì)象。
d.student_set.create(name='小明') # 創(chuàng)建一個(gè)叫小明的學(xué)生,并將他添加到學(xué)院d中
remove(obj1, obj2, ...)
從關(guān)聯(lián)的對(duì)象集中刪除指定的模型對(duì)象。刪除的是關(guān)系表中的數(shù)據(jù)
d.student_set.remove(s) # 從學(xué)院d中刪除學(xué)生s
clear() 從關(guān)聯(lián)的對(duì)象集中刪除所有的對(duì)象
d.student_set.clear() # 清除學(xué)院d中所有學(xué)生
注意對(duì)于所有類型的關(guān)聯(lián)字段,add()、create()、remove()和clear()都會(huì)馬上更新數(shù)據(jù)庫(kù)。換句話說(shuō),在關(guān)聯(lián)的任何一端,都不需要再調(diào)用save()方法
多表查詢
跨關(guān)聯(lián)關(guān)系的查詢
Django 提供一種強(qiáng)大而又直觀的方式來(lái)“處理”查詢中的關(guān)聯(lián)關(guān)系,它在后臺(tái)自動(dòng)幫你處理JOIN。 若要跨越關(guān)聯(lián)關(guān)系,只需使用關(guān)聯(lián)的模型字段的名稱,并使用雙下劃線分隔,直至你想要的字段:

舉例:
# 查詢學(xué)院名字為‘軟件’的學(xué)生的信息
Student.objects.filter(department__d_name='軟件')
#這種跨越可以是任意的深度。
#查詢學(xué)生名字中包含‘xiao’的學(xué)生的學(xué)院信息
Department.objects.filter(student__s_name__contains='xiao')
# 查詢學(xué)號(hào)為1的學(xué)生所有的課程
Course.objects.filter(student__s_id=1)
# 查詢報(bào)了課程1的所有的學(xué)生
Student.objects.filter(course__c_id=1)
# 查詢報(bào)了'python'課程的的學(xué)生的所屬學(xué)院的信息
Department.objects.filter(student__course__c_name='python') #三個(gè)表關(guān)聯(lián)查詢
總結(jié):
- Object對(duì)象獲取某一列值(或者說(shuō)是獲取某個(gè)屬性)的時(shí)候,使用點(diǎn)來(lái)獲取。我們跨表查詢時(shí),也是使用點(diǎn)來(lái)獲取。或者用_set反查詢,_set:提供了對(duì)象訪問(wèn)相關(guān)聯(lián)表數(shù)據(jù)的方法。但這種方法只能是相關(guān)類訪問(wèn)定義了關(guān)系的類(主鍵類訪問(wèn)外鍵類)。
- QuerySet查詢集做跨表查詢時(shí),使用雙下劃線"",:兩個(gè)下劃線可以生成連接查詢,查詢關(guān)聯(lián)的字段信息,可以跨表關(guān)聯(lián)查詢,只要一層接一層,可以從頭查到尾。
聚合操作
使用aggregate方法進(jìn)行數(shù)據(jù)庫(kù)的聚合操作, 使用QuerySet.aggregate 代表需要使用聚合操作,它返回的是一個(gè)字典:
- 引入對(duì)應(yīng)的聚合函數(shù)
from django.db.models import Avg, Max, Min, Count, Sum - Avg, 平均數(shù)
#查詢當(dāng)前作者的平均年齡
Author.objects.aggregate(Avg("age"))
- Max 最大數(shù)
#取最大年齡的作者
Author.objects.aggregate(Max("age"))
- Min 最小數(shù)
#取最小年齡的作業(yè)
Author.objects.aggregate(Max("age"))
- Count 統(tǒng)計(jì)行數(shù)
#統(tǒng)計(jì)有多少個(gè)作者
Author.objects.aggregate(Count("id"))
#如果需要去重
Author.objects.aggregate(Count("age", distinct=True))
- Sum 統(tǒng)計(jì)和
#獲取所有作者的年齡總和
Author.objects.aggregate(Sum("age"))
- 多個(gè)聚合結(jié)果
Author.objects.aggregate(Sum("age"),Min("age"), Max("age"))
- 自定義名稱聚合字段別名, 你的參數(shù)名就是你需要自定義的聚合結(jié)果名稱
Author.objects.aggregate(avg_age=Avg("age")) >>>{avg_age:平均年齡值}
- 使用annotate進(jìn)行聚合查詢
1 它與aggregate類似,但是aggregate的結(jié)果一定只有一個(gè)值,且aggregate執(zhí)行后就是最終結(jié)果。
2 aggregate返回的是一個(gè)字典,annotate返回的是一個(gè)QuerySet,可以繼續(xù)進(jìn)行查詢。
3 annotate的聚合結(jié)果是針對(duì)每行數(shù)據(jù)的,而不是整個(gè)查詢結(jié)果。
在博客常見(jiàn)側(cè)邊欄有分類列表,顯示博客已有的全部文章分類?,F(xiàn)在想在分類名后顯示該分類下有多少篇文章,該怎么做呢?這個(gè)就可以用到annotate函數(shù),先按類名進(jìn)行分組,然后再統(tǒng)計(jì)每個(gè)組分別為多少數(shù)量即可。 - 使用annotate進(jìn)行集合查詢
#統(tǒng)計(jì)每本書(shū)的作者有多少
Book.objects.annotate(Count("anthors"))
#統(tǒng)計(jì)每個(gè)年齡分別有多少人
# values 就等同于group by,返回的是一個(gè)字典
# values_list 就等同于group by,, 返回的是一個(gè)元祖
Author.objects.values("age").annotate(Count("id"))
事務(wù)
如果需要支持事務(wù),mysql引擎必須是InnoDB類型。
- 引入django處理事務(wù)的包
from django.db import transaction
- 使用裝飾器事務(wù)控制
ps: 使用裝飾器的事務(wù)必須是view視圖函數(shù)
ps: 通用視圖類還未提供裝飾器事務(wù)控制器
# 這個(gè)裝飾器不能在通用View視圖中使用
# 現(xiàn)在django還只提供了在view函數(shù)中使用的裝飾器
@transaction.atomic
def model_study(request):
# 使用事務(wù)裝飾器以后
# 整個(gè)view函數(shù)里面的數(shù)據(jù)庫(kù)操作
# 要么全部成功
# 要么全部失敗
# 下面的代碼在一個(gè)事務(wù)中執(zhí)行,一但出現(xiàn)異常,整個(gè)函數(shù)中所有的數(shù)據(jù)庫(kù)操作全部都會(huì)回滾
book = Book.objects.create(headline="事務(wù)操作1")
author = Author.objects.create(name="kevin", email="test@qq.com", age=28)
book.authors.add(author)
book.save()
# assert not book.headline.find("操作") >= 0, "這是敏感關(guān)鍵字"
return render(request, "model_study/model_study.html")
- 使用上下文管理器的方式
from django.db import transaction
class ViewClass(View)
def get(self, request)
# 下面的代碼在自動(dòng)提交模式下執(zhí)行(Django的默認(rèn)模式)
with transaction.atomic(): # with中的代碼,全部都會(huì)保持原子性
# 下面的代碼在一個(gè)事務(wù)中執(zhí)行,一但出現(xiàn)異常,整個(gè)with函數(shù)內(nèi)部的數(shù)據(jù)庫(kù)操作都會(huì)回滾
book = Book.objects.create(headline="事務(wù)操作3")
author = Author.objects.create(name="kevin", email="test@qq.com", age=28)
book.authors.add(author)
book.save()
assert 1==1
# raise Exception, "這里出現(xiàn)了一個(gè)bug"
ps: with 內(nèi)部最好不要使用try...catch...模塊,否則可能會(huì)影響django的事務(wù)異常判斷。
課后練習(xí)
1、創(chuàng)建一個(gè)班級(jí)的模型(名稱、班號(hào)(一對(duì)一外鍵),創(chuàng)建時(shí)間(自動(dòng)添加),修改時(shí)間(自動(dòng)更新))
2、創(chuàng)建一個(gè)班號(hào)的模型(號(hào)碼)
3、創(chuàng)建一個(gè)學(xué)生的模型(名稱、班級(jí)(多對(duì)一外鍵 ),老師(多對(duì)多),年齡,性別)
4、創(chuàng)建一個(gè)老師的模型( 名稱,年齡,性別,班級(jí)(多對(duì)一外鍵))
- app應(yīng)用models.py中建立模型類
#班號(hào)模型
class Classesnumber(models.Model): #類名代表了數(shù)據(jù)庫(kù)表名,且繼承了models.Model,類里面的字段代表數(shù)據(jù)表中的字段(name)
# 屬性=models.字段類型(選項(xiàng))
# 如果沒(méi)有添加主鍵,django會(huì)默認(rèn)添加一個(gè)ID的主鍵
classgrade_number = models.CharField(u'號(hào)碼',max_length=20) #備注也可用verbose_name
class Meta: #模型元選項(xiàng)
db_table = u'classnumber' #在數(shù)據(jù)庫(kù)中的表名,否則Django自動(dòng)生成為app名字_類名
managed = True
# 數(shù)據(jù)的默認(rèn)排序, 如果需要倒序,則添加"-"號(hào)即可,這里可以按多個(gè)排序
# 多個(gè)排序會(huì)按你的數(shù)組列表順序進(jìn)行排序
ordering = ['id','classgrade_number']
# 描述,當(dāng)查詢結(jié)果是一條記錄時(shí),它的描敘
verbose_name = u'班號(hào)' #對(duì)象的描述
# 如果查詢結(jié)果為多個(gè)記錄,則返回verbose_name_plural的描敘
verbose_name_plural = u'班號(hào)集' #復(fù)數(shù)時(shí)的描述
#班級(jí)模型
class Classesgrade(models.Model):
name = models.CharField(u'名稱',max_length=20)
create_time = models.DateTimeField(u'創(chuàng)建時(shí)間',auto_now_add=True) #auto_now_add只有第一次才會(huì)生效
update_time = models.DateTimeField(verbose_name= u'修改時(shí)間',auto_now=True)#auto_now每一次修改的動(dòng)作,都會(huì)更新一個(gè)時(shí)間
#與班級(jí)一對(duì)一關(guān)系,關(guān)聯(lián)屬性,Django會(huì)自動(dòng)建立個(gè)屬性_id字段
number = models.OneToOneField(Classesnumber)
class Meta:
db_table = 'classesgrade'
managed = True
#老師模型
class Teacher(models.Model):
name = models.CharField(u'姓名',max_length=20)
age = models.IntegerField(u'年齡')
sex = models.CharField(u'性別',max_length=2)
#老師與班級(jí)多對(duì)一,關(guān)聯(lián)屬性在多方定義
#db_constraint:bool 是否建立外鍵約束,
#to_field:string 關(guān)聯(lián)到的關(guān)聯(lián)對(duì)象的字段名稱。默認(rèn)地,Django 使用關(guān)聯(lián)對(duì)象的主鍵。
#CASCADE:級(jí)聯(lián)刪除,如果刪除,相關(guān)聯(lián)的那個(gè)也會(huì)刪除
classesno = models.ForeignKey(Classesgrade,db_constraint = True,to_field='id',on_delete = models.CASCADE)
class Meta:
db_table = 'teacher'
managed = True
#學(xué)生
class Student(models.Model):
name = models.CharField(u'姓名',max_length=20)
age = models.IntegerField(u'年齡')
sex = models.CharField(u'性別',max_length=2)
classesno = models.ForeignKey(Classesgrade,db_constraint = True,to_field='id',on_delete = models.CASCADE)
# 多對(duì)多,Django會(huì)自動(dòng)創(chuàng)建中間表
teacher = models.ManyToManyField(Teacher,related_name = 'teacher_set')
class Meta:
db_table = 'student'
managed = True
- 添加數(shù)據(jù)
班號(hào)(“001”,“002“)
老師 ("k", “28”, "男",“django框架班001”)
老師 ("山", “28”, "男",“django框架班001” )
老師 ("不", “28”, "男",“django框架班002” )
班級(jí)(“django框架班” ,“班號(hào)(001) ”,“自動(dòng)創(chuàng)建”, “自動(dòng)更新”)
班級(jí)(“django框架班” ,“班號(hào)(002) ”,“自動(dòng)創(chuàng)建”, “自動(dòng)更新”)
學(xué)生(“學(xué)生1”,20,“男”,“001 ”,[“k老師”,“山”])
學(xué)生(“學(xué)生2”,22,“女”,“002 ”,["山", “不”])
學(xué)生(“學(xué)生3”,21,“男”,“001 ”, ["k", “不”])
class AddInfor(View):
def get(self,request):
#添加班號(hào)數(shù)據(jù)
#可以用save和create方式
cnumber1 = Classesnumber.objects.create(classgrade_number = '001')
cnumber2 = Classesnumber.objects.create(classgrade_number = '002')
#添加班級(jí)數(shù)據(jù):
#如果存在外鍵關(guān)聯(lián),主表必須首先得先有數(shù)據(jù),一對(duì)一關(guān)系的添加數(shù)據(jù)
#一對(duì)一賦值必須保持一個(gè)對(duì)象只對(duì)應(yīng)一個(gè)外鍵
cnumber3 = Classesnumber.objects.get(pk=1) #1對(duì)1,先取出主表的pk=1對(duì)象
Classesgrade.objects.create(name = u'django框架班',number = cnumber3 ) #再賦給外鍵
cnumber4 = Classesnumber.objects.get(pk=2)
cgrade = Classesgrade(name = u'django框架班',number = cnumber4)
cgrade.save()
# 添加老師數(shù)據(jù):
#獲取班級(jí)對(duì)象
cgrade1 = Classesgrade.objects.get(pk=1) #1對(duì)多,先取出主表的pk=1對(duì)象
cgrade2 = Classesgrade.objects.get(pk=2) #1對(duì)多,先取出主表的pk=2對(duì)象
# # 通過(guò)獲取一端對(duì)象,則這里要用類屬性而不是表字段的名字
Teacher.objects.create(name = u'k',age = 28,sex = u'男',classesno = cgrade1)
Teacher.objects.create(name = u'山',age = 28,sex = u'男',classesno = cgrade1)
Teacher(name = u'不',age = 28,sex = u'男',classesno = cgrade2).save()
#添加學(xué)生數(shù)據(jù)views.py中:
#與班級(jí),多對(duì)一外鍵
stu1 = Student()
stu1.name = u'學(xué)生1'
stu1.age = 20
stu1.sex = u'男'
stu1.classesno = cgrade1
stu1.save()
stu2 = Student(name = u'學(xué)生2',age = 22,sex = u'女',classesno = cgrade2)
stu2.save()
stu3 = Student.objects.create(name = u'學(xué)生3',age = 21,sex = u'男',classesno = cgrade1)
#與老師多對(duì)多
#多對(duì)多的添加,需要使用add方法
#多對(duì)多的添加,必須主類必須在數(shù)據(jù)庫(kù)已經(jīng)存在
tch1 = Teacher.objects.get(name__exact= u'k')
tch2 = Teacher.objects.get(name__exact= u'山')
tch3 = Teacher.objects.get(name__exact= u'不')
stu1.teacher.add(tch1)
stu1.teacher.add(tch2)
stu1.save()
stu2.teacher.add(tch2,tch3)
stu2.save()
stu3.teacher.add(tch1,tch3)
stu3.save()
return render(request,'result.html',locals())
- 查詢數(shù)據(jù)views.py中
#app應(yīng)用urls.py中
urlpatterns = [
url(r'^register/$', views.Register.as_view(),name='register'),
url(r'^login/$', views.Login.as_view(),name = 'login'),
url(r'^index/$', views.Index.as_view(),name='index'),
url(r'^logout/$', views.Logout.as_view(),name='logout')
]
class QueryInfor(View):
def get(self,request):
#查詢性別為男的學(xué)生
stu_boys = Student.objects.filter(sex__exact = u'男')
#查詢年齡大于20歲的學(xué)生
stu_20 = Student.objects.filter(age__gt = 20)
#獲取所有學(xué)生、并按年齡排序
stu_all = Student.objects.all().order_by('age')
#獲取所有學(xué)生并排除性別為女的學(xué)生
stu_nogirls = Student.objects.exclude(sex = u'女')
#獲取學(xué)生總數(shù)
stu_sum = Student.objects.count()
#獲取最后創(chuàng)建的班級(jí)
last_grade = Classesgrade.objects.latest('create_time')
cgrade1 = Classesgrade.objects.get(pk = 1)
cgrade2 = Classesgrade.objects.get(pk = 2)
#查詢班級(jí)下老師
#本身班級(jí)對(duì)象是沒(méi)有老師屬性,django提供的一個(gè)反查機(jī)制
# 如果設(shè)置related_name, 我們就通過(guò)related_name反查
# 如果沒(méi)有設(shè)置, django默認(rèn)設(shè)置的是反查class的小寫(xiě)名字
# related_name 可以當(dāng)成反查所用的別名
tchs1 = cgrade1.teacher_set.all() #xxx_set 實(shí)際返回的是一個(gè)空值,如需訪問(wèn)它們,則要進(jìn)行一個(gè)查詢QuerySet操作
tchs2 = cgrade2.teacher_set.all()
#查詢班級(jí)下學(xué)生
stu1 = cgrade1.student_set.all()
stu2 = cgrade2.student_set.all()
#查詢一個(gè)班級(jí)的編號(hào),1對(duì)1 反查
cgradeno1 =cgrade1.number #cgrade1.number是個(gè)<Classesnumber: Classesnumber object>
cgradeno2 = cgrade2.number
#查詢年齡最大的學(xué)生
sage = Student.objects.aggregate(max_age = Max('age')) #以字典形式返回年齡最大值,{'age__max': 22}
maxage_stu = Student.objects.filter(age = sage['max_age'])
#filter(**kwargs)方法:根據(jù)參數(shù)提供的提取條件,獲取一個(gè)過(guò)濾后的QuerySet。所以在前端不能直接獲取對(duì)象的方式來(lái),需要遍歷來(lái)獲取,即使只有一個(gè);
#查詢年齡最小的學(xué)生
sage = Student.objects.aggregate(Min('age')) #以字典形式返回年齡最大值,{'age__max': 22}
minage_stu = Student.objects.filter(age = sage[sage.keys()[0]]) #sage.keys()[0]獲取字典的鍵
#avgage_stu查詢學(xué)生的平均年齡
sage = Student.objects.aggregate(Avg('age'))
for key,value in sage.items():
keys = key
age = value
#查詢每個(gè)年齡的學(xué)生數(shù)量,按年齡進(jìn)行分組,然后統(tǒng)計(jì)數(shù)量select age,count(age) from student group by age;
agestucount = Student.objects.values('age').annotate(Count('id')) #annotate返回的是一個(gè)QuerySet,可以繼續(xù)進(jìn)行查詢
return render(request,'queryInfor.html',locals())
頁(yè)面效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>查詢信息</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<h2>1.查詢性別為男的學(xué)生:</h2>
<p>
{%for stu_boy in stu_boys%}
姓名:{{stu_boy.name}}<br/>
性別:{{stu_boy.sex}}<br/>
年齡:{{stu_boy.age}}<br/>
班級(jí):{{stu_boy.classesno_id}}<br/>
{%endfor%}
</p>
<hr/>
<h2>2.查詢年齡大于20歲的學(xué)生:</h2>
<p>
{%for stu in stu_20%}
姓名:{{stu.name}}<br/>
性別:{{stu.sex}}<br/>
年齡:{{stu.age}}<br/>
班級(jí):{{stu.classesno_id}}<br/>
{%endfor%}
</p>
<hr/>
<h2>3.獲取所有學(xué)生、并按年齡排序:</h2>
<p>
{%for stu in stu_all%}
姓名:{{stu.name}}<br/>
性別:{{stu.sex}}<br/>
年齡:{{stu.age}}<br/>
班級(jí):{{stu.classesno_id}}<br/>
{%endfor%}
</p>
<hr/>
<h2>4.獲取所有學(xué)生并排除性別為女的學(xué)生:</h2>
<p>
{%for stu in stu_nogirls%}
姓名:{{stu.name}}<br/>
性別:{{stu.sex}}<br/>
年齡:{{stu.age}}<br/>
班級(jí):{{stu.classesno_id}}<br/>
{%endfor%}
</p>
<hr/>
<h2>5.獲取學(xué)生總數(shù):</h2>
<p>
{{stu_sum}}
</p>
<hr/>
<h2>6.獲取最后創(chuàng)建的班級(jí):</h2>
<p>
名稱:{{last_grade.name}}<br/>
創(chuàng)建時(shí)間:{{last_grade.create_time}}<br/>
更新時(shí)間:{{last_grade.update_time}}<br/>
對(duì)應(yīng)班號(hào):{{last_grade.number_id}}
</p>
<hr/>
<h2>11.查詢一個(gè)班級(jí)下有那些老師:</h2>
<p>
{{cgrade1.name}}第{{cgrade1.number.id}}個(gè)班老師:<br/>
{%for tch in tchs1%}
姓名:{{tch.name}}<br/>
性別:{{tch.sex}}<br/>
年齡:{{tch.age}}<br/>
班級(jí):{{tch.classesno_id}}<br/> <!--tch.classesno 對(duì)象.類屬性形式不行,因?yàn)檫€是一個(gè)對(duì)象,要么用對(duì)象.表字段名,要么對(duì)象.類屬性.主表主鍵 -->
{%endfor%}
<hr/>
{{cgrade2.name}}第{{cgrade2.number_id}}個(gè)班老師:<br/>
{%for tch in tchs2%}
姓名:{{tch.name}}<br/>
性別:{{tch.sex}}<br/>
年齡:{{tch.age}}<br/>
班級(jí):{{tch.classesno.id}}<br/>
{%endfor%}
</p>
<h2>22.查詢一個(gè)班級(jí)下有那些學(xué)生:</h2>
<p>
{{cgrade1.name}}第{{cgrade1.number.id}}個(gè)班學(xué)生:<br/>
{%for stu in stu1%}
姓名:{{stu.name}}<br/>
性別:{{stu.sex}}<br/>
年齡:{{stu.age}}<br/>
班級(jí):{{stu.classesno_id}}<br/>
{%endfor%}
<hr/>
{{cgrade2.name}}第{{cgrade2.number_id}}個(gè)班學(xué)生:<br/>
{%for stu in stu2%}
姓名:{{stu.name}}<br/>
性別:{{stu.sex}}<br/>
年齡:{{stu.age}}<br/>
班級(jí):{{stu.classesno_id}}<br/>
{%endfor%}
</p>
<h2>33.查詢一個(gè)班級(jí)的編號(hào):</h2>
<p>
第{{cgrade1.number_id}}個(gè)班編號(hào):{{cgradeno1.classgrade_number}}<br/>
第{{cgrade2.number_id}}個(gè)班編號(hào):{{cgrade2.number.classgrade_number}}
</p>
<h2>44、查詢年紀(jì)最大的學(xué)生</h2>
<p>
{% for stu in maxage_stu %}
姓名:{{stu.name}}<br/>
性別:{{stu.sex}}<br/>
年齡:{{stu.age}}<br/>
班級(jí):{{stu.classesno_id}}<br/>
{% endfor %}
</p>
<h2>55、查詢年紀(jì)最小的學(xué)生</h2>
<p>
{% for stu in minage_stu %}
姓名:{{stu.name}}<br/>
性別:{{stu.sex}}<br/>
年齡:{{stu.age}}<br/>
班級(jí):{{stu.classesno_id}}<br/>
{% endfor %}
</p>
<h2>66、查詢學(xué)生的平均年齡</h2>
<p>
平均{{keys}}:{{value}}z
</p>
<h2>77、查詢每個(gè)年齡的學(xué)生數(shù)量</h2>
{% for dic in agestucount%} <!--agestucount是一個(gè)QuerySet,需要從中迭代出來(lái) -->
{% for age,countstu in dic.items %} <!--再將每一個(gè)遍歷出來(lái)的字典通過(guò)items將鍵值取出來(lái) -->
{{age}}:{{countstu}}
{% endfor %}
;<br/>
{% endfor %}
</body>
</html>