Django ORM 基本操作

发布时间 2023-12-18 15:17:02作者: 小天狼鑫

本次sql大部分习题出自知乎以为网友,对原sql感兴趣的各位朋友,可以去参考知乎上的这位朋友:

https://www.zhihu.com/tardis/bd/art/38354000?source_id=1001

我们在他的基础上,进行sql改造,成为我们Django ORM机制下的ORM语法。本次教程的面向人群:我们默认你会使用Django,至少能够自己启动一个项目。

相关的Django基础,将不再赘述,如果你对Django本身的基础并不好,那么希望你可以先去学习Django基础,然后再来此处查看Django的ORM基本操作。

具体的表结构,我们参考知乎上面的,你们也可以自己看一下。

class Student(models.Model):
    class SexEnum:
        M = 1
        F = 0

    ChoicesSex = (
        ("男性", 1),
        ("女性", 0),
    )
    xuehao = models.IntegerField("学号", 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("教师号", 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"

准备好上面的model后,我们使用makemigrations    migrate    将数据迁移至数据库。

数据库迁移结束后,我们创建基本的数据链条。

由于编写时,记录缺失了一部分,大家自己将student、teacher表中的数据补全,我这里提供出course和score的表创建语句。

Course.objects.create(kechengid=1,kechengname="语文",jiaoshiid=Teacher.objects.filter(teacherid=1).first())
Course.objects.create(kechengid=2,kechengname="数学",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="数学",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)

 

 

 

 

 

我们将数据库里面的数据贴出来供大家参考。

准备好数据后,我们开始今天的ORM基本操作。

  1. 查询姓 “猴” 的学生名单
    Student.objects.filter(name__startswith="")
    # <QuerySet [<Student: Student object (1)>]>
  2. 查询姓氏中,最后一个是“猴”的学生的名单
    Student.objects.filter(name__endswith="")
    # <QuerySet [<Student: Student object (2)>]>
  3. 查询名字中 带有 “猴” 的名单
    Student.objects.filter(name__contains="")
    # <QuerySet [<Student: Student object (1)>, <Student: Student object (2)>]>
  4. 查询姓 “孟” 老师的个数
    Teacher.objects.filter(teachername__contains="").count()
    # 1

  以上是有关模糊查询的相关操作。在orm中,__有很神奇的用法,我们一一进行讲解:

 

in : 后面接一个范围 --》 我们可以是 id__in = [1,2,3,4], 也可以是后面跟一个queryset对象集。

举例说明:

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: 精确匹配 --》 你输入的东西,进行精确匹配

iexact: 精确,但不区分大小写, 精确匹配

regex: 正则匹配,调用数据库正则匹配方法,mysql:REGEXP_LIKE

ranger: 在 .... .... 范围内: __ranger = [10, 1000] 范围规定在十到一千之内

contains : 模糊匹配,但不忽略大小写。

endswith: 以 ....... 为结尾的匹配,但不忽略大小写。

startswith: 以 ...... 为开头的匹配,但不忽略大小写。

icontains: 模糊匹配,但是忽略大小写。

iendswith: 以 ....... 为结尾的匹配,但忽略大小写。

istartswith: 以 ...... 为开头的匹配,但忽略大小写。

lt:小于   对应英文:less than

gt:大于  对应英文: geater than

lte:不大于(小于等于) less than or equal

gte:不小于 (大于等于) geater than or equal

ORM的双下滑查询还有很多,感兴趣的可以自己找找看,对日期啊,字符串,数字这类的都不一样,这里仅列出常用的。

5、查询课程编号为 “2” 的总成绩

Score.objects.filter(kechengid__kechengid=2).aggregate(chengji_sum=models.Sum("chengji"))
# {'chengji_sum': 230}

思路:我们要查成绩,我们从表结构可知,成绩表与课程表是具有外键关联的,所以我们先把id为2的数据都查出来,以“__外键名”的形式,就可以获取到kechengid是2的全部成绩,然后在使用aggregate函数进行聚合。

aggregate函数基本使用法则:queryset对象支持聚合操作,ORM的聚合操作放在queryset的aggregate方法里面,使用models.xxxx的形式进行聚合。

本题中:我们需要对kechengid取出来之后的数据进行sum求和处理,我们就可以在aggregate函数里面入参是你自己想的名字+modles.Sum('chengji')的

形式进行sum操作。

6、查询选择了课程的学生数

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 的个数聚合,然后找到学号和刚才查完的数据,把聚合后的个数里面的小于零的过滤掉。

annotate函数基本使用法则:它不像aggregate一样,agg返回返回你需要的字段,ann将你后面生成的字段动态添加到查询集里面去,使得我们可以对其进行其他操作。

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
数学 90 60
英语 80 60

"""

思路:从课程表里面,查出score表中chengji的外字段的最大值与最小值,然后聚合出来

在有外键的表中,我们可以使用表明小写来查询,这是Django ORM的反、正向查询手段。具体的反、正向查询你可以自行百度,很简单的。

主要你需要知道与记住的是:不论外键在哪张表里面,查什么就用什么,比如你想查询各科成绩,我们的查询主体是各科,也可以是成绩,不同的查询,使用不同的正或反向查询。

8、查询每科课程被选择的学生数

思路:因为课程表与学生表是没有关系的,所以我们使用成绩表进行查,先拿出课程表的课程id号,然后计算学号个数,进行聚合。

Score.objects.values("kechengid").annotate(xuesum=models.Count("xuehao"))
# <QuerySet [{'kechengid': 1, 'xuesum': 2}, {'kechengid': 2, 'xuesum': 3}, {'kechengid': 3, 'xuesum': 3}]>

9、查询男女人数

思路:先把student里面需要的分组字段拿出来,然后再聚合计算

Student.objects.values("gender").annotate(ren=models.Count("gender"))
# <QuerySet [{'gender': True, 'ren': 3}, {'gender': False, 'ren': 2}]>

10、查询平均成绩大于75分的学生的学号和平均成绩

思路:计算每一个学生的平均成绩,然后将大于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、查询至少选两门课程的学生的学号

思路:查出学号,然后根据课程id计数分类,最后将大于等于二的全部拿出来

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、查询同名同性的学生名单并统计同名人数

思路:首先是同名\同性的取出来,然后根据姓名统计人数,最后将统计聚合之后的结果,大于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、查询不及格的课程并按课程号从大到小排列

思路:将成绩小于八十的都查出来,然后按照课程id进行倒叙。

Score.objects.filter(chengji__lt=80).order_by("-kechengid__kechengid")

倒叙排序:在order_by里面的字段加上 - 号即可。

14、查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列

思路:查出课程ID,然后给成绩取平均值,然后按照平均成绩升序,课程号降序的形式排序

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、检索课程编号为“2”且分数小于81的学生学号,结果按分数降序排列

思路:首先,主语是查询学号,条件是课程编号为2并且分数小于81的学生号。正向查询成绩、和成绩号

Student.objects.filter(score__chengji__lt=81, score__kechengid=2).order_by("-score__chengji")

16、统计每门课程的学生选修人数(超过2人的课程才统计)、要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序

思路:首先是你需要谁,就查出来谁,你需要课程号,和选修人数,查出课程号,我们方便查看,顺便查出对应的课程名,然后按照课程ID计数,然后将大于2的全部都拿出来

Score.objects.values("kechengid","kechengid__kechengname").annotate(renshu=models.Count("kechengid")).filter(renshu__gt=2).order_by("-kechengid","renshu")

17、查询两门以上不及格课程的同学的学号及其平均成绩

思路:目的:同学的学号 and 平均成绩 无论是成绩表还是学生表,两个表之间存在内外键,所以用两个表哪个表查都可以。无非就是正反向查询问题。

Student.objects.filter(score__chengji__lt=81).annotate(ave=models.Avg("score__chengji"))

18、查询学生的总成绩并将其排名

Student.objects.values("name").annotate(sum=models.Sum("score__chengji")).filter(sum__isnull=False).order_by("-sum")

19、查询平均成绩大于73分的学生的学号和平均成绩

s = Student.objects.annotate(avg=models.Avg("score__chengji")).filter(avg__isnull=False)
sf = s.filter(avg__gte=73)

本次就像分享这么多吧,看完这些,我相信你对Django ORM的基本操作已经有了一些理解,使用在实战上是没问题的了,好好学习,天天向上!