Django ORM 基本操作
本次sql大部分習(xí)題出自知乎以為網(wǎng)友,對(duì)原sql感興趣的各位朋友,可以去參考知乎上的這位朋友:
https://www.zhihu.com/tardis/bd/art/38354000?source_id=1001
我們?cè)谒幕A(chǔ)上,進(jìn)行sql改造,成為我們Django ORM機(jī)制下的ORM語法。本次教程的面向人群:我們默認(rèn)你會(huì)使用Django,至少能夠自己啟動(dòng)一個(gè)項(xiàng)目。
相關(guān)的Django基礎(chǔ),將不再贅述,如果你對(duì)Django本身的基礎(chǔ)并不好,那么希望你可以先去學(xué)習(xí)Django基礎(chǔ),然后再來此處查看Django的ORM基本操作。
具體的表結(jié)構(gòu),我們參考知乎上面的,你們也可以自己看一下。
class Student(models.Model): class SexEnum: M = 1 F = 0 ChoicesSex = ( ("男性", 1), ("女性", 0), ) xuehao = models.IntegerField("學(xué)號(hào)", primary_key=True, default=1) name = models.CharField("姓名", max_length=255, default="0") brith = models.DateField("生日", default=datetime.now) gender = models.BooleanField("性別", choices=ChoicesSex, default=SexEnum.M) class Meta: db_table = "student"
class Teacher(models.Model): teacherid = models.IntegerField("教師號(hào)", primary_key=True, default=1) teachername = models.CharField("老師名字", max_length=255, null=True) class Meta: db_table = "teacher"
class Course(models.Model): kechengid = models.IntegerField("課程ID", primary_key=True, default=1) kechengname = models.CharField("課程名稱", max_length=255) jiaoshiid = models.ForeignKey(Teacher, on_delete=models.CASCADE) class Meta: db_table = "course"
class Score(models.Model): xuehao = models.ForeignKey(Student, on_delete=models.CASCADE) kechengid = models.ForeignKey(Course, on_delete=models.CASCADE) chengji = models.IntegerField("成績") class Meta: unique_together = (("xuehao", "kechengid"),) db_table = "score"
準(zhǔn)備好上面的model后,我們使用makemigrations migrate 將數(shù)據(jù)遷移至數(shù)據(jù)庫。
數(shù)據(jù)庫遷移結(jié)束后,我們創(chuàng)建基本的數(shù)據(jù)鏈條。
由于編寫時(shí),記錄缺失了一部分,大家自己將student、teacher表中的數(shù)據(jù)補(bǔ)全,我這里提供出course和score的表創(chuàng)建語句。
Course.objects.create(kechengid=1,kechengname="語文",jiaoshiid=Teacher.objects.filter(teacherid=1).first()) Course.objects.create(kechengid=2,kechengname="數(shù)學(xué)",jiaoshiid=Teacher.objects.filter(teacherid=2).first()) Course.objects.create(kechengid=3,kechengname="英語",jiaoshiid=Teacher.objects.filter(teacherid=3).first()) Course.objects.create(kechengid=2,kechengname="數(shù)學(xué)",jiaoshiid=1) Course.objects.create(kechengid=3,kechengname="英語",jiaoshiid=3) Score.objects.create(xuehao=Student.objects.filter(xuehao=1).first(),kechengid=Course.objects.filter(kechengid=1).first(), chengji=80) Score.objects.create(xuehao=Student.objects.filter(xuehao=1).first(),kechengid=Course.objects.filter(kechengid=2).first(), chengji=90) Score.objects.create(xuehao=Student.objects.filter(xuehao=1).first(),kechengid=Course.objects.filter(kechengid=3).first(), chengji=99) Score.objects.create(xuehao=Student.objects.filter(xuehao=2).first(),kechengid=Course.objects.filter(kechengid=2).first(), chengji=60) Score.objects.create(xuehao=Student.objects.filter(xuehao=2).first(),kechengid=Course.objects.filter(kechengid=3).first(), chengji=80) Score.objects.create(xuehao=Student.objects.filter(xuehao=3).first(),kechengid=Course.objects.filter(kechengid=1).first(), chengji=80) Score.objects.create(xuehao=Student.objects.filter(xuehao=3).first(),kechengid=Course.objects.filter(kechengid=2).first(), chengji=80) Score.objects.create(xuehao=Student.objects.filter(xuehao=3).first(),kechengid=Course.objects.filter(kechengid=3).first(), chengji=80)




我們將數(shù)據(jù)庫里面的數(shù)據(jù)貼出來供大家參考。
準(zhǔn)備好數(shù)據(jù)后,我們開始今天的ORM基本操作。
-
查詢姓 “猴” 的學(xué)生名單
Student.objects.filter(name__startswith="猴")
# <QuerySet [<Student: Student object (1)>]> -
查詢姓氏中,最后一個(gè)是“猴”的學(xué)生的名單
Student.objects.filter(name__endswith="猴") # <QuerySet [<Student: Student object (2)>]>
-
查詢名字中 帶有 “猴” 的名單
Student.objects.filter(name__contains="猴") # <QuerySet [<Student: Student object (1)>, <Student: Student object (2)>]>
-
查詢姓 “孟” 老師的個(gè)數(shù)
Teacher.objects.filter(teachername__contains="孟").count() # 1
以上是有關(guān)模糊查詢的相關(guān)操作。在orm中,__有很神奇的用法,我們一一進(jìn)行講解:

in : 后面接一個(gè)范圍 --》 我們可以是 id__in = [1,2,3,4], 也可以是后面跟一個(gè)queryset對(duì)象集。
舉例說明:
Score.objects.filter(xuehao_id__in=Student.objects.filter(xuehao__in=[1, 2])).query """ SELECT `score`.`id`, `score`.`xuehao_id`, `score`.`kechengid_id`, `score`.`chengji` FROM `score` WHERE `score`.`xuehao_id` IN (SELECT U0.`xuehao` FROM `student` U0 WHERE U0.`xuehao` IN (1, 2)) """
exact: 精確匹配 --》 你輸入的東西,進(jìn)行精確匹配
iexact: 精確,但不區(qū)分大小寫, 精確匹配
regex: 正則匹配,調(diào)用數(shù)據(jù)庫正則匹配方法,mysql:REGEXP_LIKE
ranger: 在 .... .... 范圍內(nèi): __ranger = [10, 1000] 范圍規(guī)定在十到一千之內(nèi)
contains : 模糊匹配,但不忽略大小寫。
endswith: 以 ....... 為結(jié)尾的匹配,但不忽略大小寫。
startswith: 以 ...... 為開頭的匹配,但不忽略大小寫。
icontains: 模糊匹配,但是忽略大小寫。
iendswith: 以 ....... 為結(jié)尾的匹配,但忽略大小寫。
istartswith: 以 ...... 為開頭的匹配,但忽略大小寫。
lt:小于 對(duì)應(yīng)英文:less than
gt:大于 對(duì)應(yīng)英文: geater than
lte:不大于(小于等于) less than or equal
gte:不小于 (大于等于) geater than or equal
ORM的雙下滑查詢還有很多,感興趣的可以自己找找看,對(duì)日期啊,字符串,數(shù)字這類的都不一樣,這里僅列出常用的。
5、查詢課程編號(hào)為 “2” 的總成績
Score.objects.filter(kechengid__kechengid=2).aggregate(chengji_sum=models.Sum("chengji")) # {'chengji_sum': 230}
思路:我們要查成績,我們從表結(jié)構(gòu)可知,成績表與課程表是具有外鍵關(guān)聯(lián)的,所以我們先把id為2的數(shù)據(jù)都查出來,以“__外鍵名”的形式,就可以獲取到kechengid是2的全部成績,然后在使用aggregate函數(shù)進(jìn)行聚合。
aggregate函數(shù)基本使用法則:queryset對(duì)象支持聚合操作,ORM的聚合操作放在queryset的aggregate方法里面,使用models.xxxx的形式進(jìn)行聚合。
本題中:我們需要對(duì)kechengid取出來之后的數(shù)據(jù)進(jìn)行sum求和處理,我們就可以在aggregate函數(shù)里面入?yún)⑹悄阕约合氲拿?modles.Sum('chengji')的
形式進(jìn)行sum操作。
6、查詢選擇了課程的學(xué)生數(shù)
Student.objects.distinct().annotate(scoreid=models.Count("score")).values("xuehao","scoreid").filter(scoreid__gt=0) # <QuerySet [{'xuehao': 1, 'scoreid': 3}, {'xuehao': 2, 'scoreid': 2}, {'xuehao': 3, 'scoreid': 3}]>
思路:查出 student 表中 score 的個(gè)數(shù)聚合,然后找到學(xué)號(hào)和剛才查完的數(shù)據(jù),把聚合后的個(gè)數(shù)里面的小于零的過濾掉。
annotate函數(shù)基本使用法則:它不像aggregate一樣,agg返回返回你需要的字段,ann將你后面生成的字段動(dòng)態(tài)添加到查詢集里面去,使得我們可以對(duì)其進(jìn)行其他操作。
7、查詢各科成績的最高值和最低值
qs = Course.objects.annotate(maxs=models.Max("score__chengji"), mins=models.Min("score__chengji")) for i in qs: print(i.kechengname,i.maxs,i.mins)
"""
語文 80 60
數(shù)學(xué) 90 60
英語 80 60
"""
思路:從課程表里面,查出score表中chengji的外字段的最大值與最小值,然后聚合出來
在有外鍵的表中,我們可以使用表明小寫來查詢,這是Django ORM的反、正向查詢手段。具體的反、正向查詢你可以自行百度,很簡單的。
主要你需要知道與記住的是:不論外鍵在哪張表里面,查什么就用什么,比如你想查詢各科成績,我們的查詢主體是各科,也可以是成績,不同的查詢,使用不同的正或反向查詢。
8、查詢每科課程被選擇的學(xué)生數(shù)
思路:因?yàn)檎n程表與學(xué)生表是沒有關(guān)系的,所以我們使用成績表進(jìn)行查,先拿出課程表的課程id號(hào),然后計(jì)算學(xué)號(hào)個(gè)數(shù),進(jìn)行聚合。
Score.objects.values("kechengid").annotate(xuesum=models.Count("xuehao"))
# <QuerySet [{'kechengid': 1, 'xuesum': 2}, {'kechengid': 2, 'xuesum': 3}, {'kechengid': 3, 'xuesum': 3}]>
9、查詢男女人數(shù)
思路:先把student里面需要的分組字段拿出來,然后再聚合計(jì)算
Student.objects.values("gender").annotate(ren=models.Count("gender"))
# <QuerySet [{'gender': True, 'ren': 3}, {'gender': False, 'ren': 2}]>
10、查詢平均成績大于75分的學(xué)生的學(xué)號(hào)和平均成績
思路:計(jì)算每一個(gè)學(xué)生的平均成績,然后將大于75分的取出來
b = Score.objects.values("xuehao").annotate(avg=models.Avg("chengji")) b.filter(avg__gt=60) """ <QuerySet [{'xuehao': 1, 'avg': 76.6667}, {'xuehao': 2, 'avg': 70.0}, {'xuehao': 3, 'avg': 73.3333}]> <QuerySet [{'xuehao': 1, 'avg': 76.6667}]> """
11、查詢至少選兩門課程的學(xué)生的學(xué)號(hào)
思路:查出學(xué)號(hào),然后根據(jù)課程id計(jì)數(shù)分類,最后將大于等于二的全部拿出來
Score.objects.values("xuehao__xuehao").annotate(count=models.Count("kechengid")).filter(count__gte=2)
# <QuerySet [{'xuehao__xuehao': 1, 'count': 3}, {'xuehao__xuehao': 2, 'count': 2}, {'xuehao__xuehao': 3, 'count': 3}]>
12、查詢同名同性的學(xué)生名單并統(tǒng)計(jì)同名人數(shù)
思路:首先是同名\同性的取出來,然后根據(jù)姓名統(tǒng)計(jì)人數(shù),最后將統(tǒng)計(jì)聚合之后的結(jié)果,大于1的取出來。
Student.objects.values("name", "gender").annotate(name_count=models.Count("name")).filter(name_count__gt=1) # <QuerySet [{'name': '小猴', 'gender': False, 'name_count': 2}]>
13、查詢不及格的課程并按課程號(hào)從大到小排列
思路:將成績小于八十的都查出來,然后按照課程id進(jìn)行倒敘。
Score.objects.filter(chengji__lt=80).order_by("-kechengid__kechengid")
倒敘排序:在order_by里面的字段加上 - 號(hào)即可。
14、查詢每門課程的平均成績,結(jié)果按平均成績升序排序,平均成績相同時(shí),按課程號(hào)降序排列
思路:查出課程ID,然后給成績?nèi)∑骄?,然后按照平均成績升序,課程號(hào)降序的形式排序
Score.objects.values("kechengid").annotate(avg=models.Avg("chengji")).order_by("-avg", "kechengid") # <QuerySet [{'kechengid': 2, 'avg': 76.6667}, {'kechengid': 3, 'avg': 73.3333}, {'kechengid': 1, 'avg': 70.0}]>
15、檢索課程編號(hào)為“2”且分?jǐn)?shù)小于81的學(xué)生學(xué)號(hào),結(jié)果按分?jǐn)?shù)降序排列
思路:首先,主語是查詢學(xué)號(hào),條件是課程編號(hào)為2并且分?jǐn)?shù)小于81的學(xué)生號(hào)。正向查詢成績、和成績號(hào)
Student.objects.filter(score__chengji__lt=81, score__kechengid=2).order_by("-score__chengji")
16、統(tǒng)計(jì)每門課程的學(xué)生選修人數(shù)(超過2人的課程才統(tǒng)計(jì))、要求輸出課程號(hào)和選修人數(shù),查詢結(jié)果按人數(shù)降序排序,若人數(shù)相同,按課程號(hào)升序排序
思路:首先是你需要誰,就查出來誰,你需要課程號(hào),和選修人數(shù),查出課程號(hào),我們方便查看,順便查出對(duì)應(yīng)的課程名,然后按照課程ID計(jì)數(shù),然后將大于2的全部都拿出來
Score.objects.values("kechengid","kechengid__kechengname").annotate(renshu=models.Count("kechengid")).filter(renshu__gt=2).order_by("-kechengid","renshu")
17、查詢兩門以上不及格課程的同學(xué)的學(xué)號(hào)及其平均成績
思路:目的:同學(xué)的學(xué)號(hào) and 平均成績 無論是成績表還是學(xué)生表,兩個(gè)表之間存在內(nèi)外鍵,所以用兩個(gè)表哪個(gè)表查都可以。無非就是正反向查詢問題。
Student.objects.filter(score__chengji__lt=81).annotate(ave=models.Avg("score__chengji"))
18、查詢學(xué)生的總成績并將其排名
Student.objects.values("name").annotate(sum=models.Sum("score__chengji")).filter(sum__isnull=False).order_by("-sum")
19、查詢平均成績大于73分的學(xué)生的學(xué)號(hào)和平均成績
s = Student.objects.annotate(avg=models.Avg("score__chengji")).filter(avg__isnull=False) sf = s.filter(avg__gte=73)
本次就像分享這么多吧,看完這些,我相信你對(duì)Django ORM的基本操作已經(jīng)有了一些理解,使用在實(shí)戰(zhàn)上是沒問題的了,好好學(xué)習(xí),天天向上!
浙公網(wǎng)安備 33010602011771號(hào)