• Django的学习进阶(三)————ORM


    django框架是将数据库信息进行了封装,采取了

    类——>数据表

    对象——>记录

    属性——>字段

    通过这种一一对应方式完成了orm的基本映射
    官方文档:https://docs.djangoproject.com/en/2.2/

    一、表单
    models中每一个继承于models.Model的类就是一张数据表
    如:class AddressInfo就是一张关于地址的数据表
    官方文档:https://docs.djangoproject.com/en/2.2/topics/db/models/

    二、字段
    文档地址:https://docs.djangoproject.com/en/2.2/ref/models/fields/
    (1)字段设计
    1.自增长字段(default=int)

    # 自增长字段
    Auto = models.AutoField()  # 默认为整型
    BigAuto = models.BigAutoField()  # 比Auto大

     

    2.二进制的数据

    # 二进制字段
    Binary = models.BinaryField()  # 二进制字段

     

    3.boolean类型

    # Boolean类型
    Boolean = models.BooleanField()  # 不为空
    NullBoolean = models.NullBooleanField()  # 为空

     

    4.整型

    # 整型
    PositiveSmallInteger = models.PositiveSmallIntegerField()  # 能存取五个字节的大小
    SmallInteger = models.SmallIntegerField()  # 能存取六个字节的大小  可以是正整数也可以是负整数
    PositiveInteger = models.PositiveIntegerField()  # 10个字节大小的正整数
    Integer = models.IntegerField()  # 11个字节大小的正整数
    BigInteger = models.BigIntegerField()  # 20个字节大小的整形


    5.字符型

    # 字符串类型
    Char = models.CharField()  # varchar
    Text = models.TextField()  # longtext

     

    6.时间类型

    # 时间日期类型
    Date = models.DateField()  # 年月日
    DateTime = models.DateTimeField()  # 年月日时分秒
    Duration = models.DurationField()  # 一段时间 int 底层用Python timedelta实现

     

    7.浮点型

    # 浮点型
    Float = models.FloatField()  # 浮点型
    Decimal = models.DecimalField()  # 需要指定整数多少位  小数多少位

     

    8.其他字段

    # 其他字段
    Email = models.EmailField()  # 邮箱
    Image = models.ImageField()  # 图片
    File = models.FileField()  # 文件
    FilePath = models.FilePathField()  # 文件路径
    URL = models.URLField()  # 网址
    UUID = models.UUIDField()  # 通用唯一识别码
    GenericIpAddress = models.GenericIPAddressField()  # ip地址  ipv4的地址 或者是ipv6的地址


    (2)字段参数设计
    1.通用参数

    # db_column="" 指定在数据库中的参数
    # primary_key=True 设置主键 True
    # verbose_name="" 设置别名
    # unique=True 设置字段是否唯一
    # null=True, blank=True, db_index=True null是表中的字段是否为空 blank是表单提交的数据要和null保持一致 否则就会出现错误 同时给字段建立索引
    # help_text="" 建立帮助文档
    # editable=False 使用户不可以修改
    # max_length = 20 指定最大长度

     

    2.个别参数具有的字段

    # date类型: unique_for_date=True 设置日期必须唯一 还有月和年
    # date类型: auto_now_add=True 增加记录时的时间 插入数据的时间
    # date类型: auto_now=True 更新当前记录的时间 更新数据的时间
    # Decimal类型: max_digits=4 总共多少位, decimal_places=2 小数的位数

     

    3.关系型字段

    # related_name='' 外键查询的信息
    # on_delete: 当外键不在的时候进行什么操作 作为关系型字段的必须参数(默认顺序是外键表to和on_delete)
    # on_delete的六种模式
    """
    models.CASCADE: 删除级联  A表记录被删除B表记录也会被删除 默认 要设定null=True blank=True
    models.PROTECT: 删除时 会报PROTECT ERROR异常
    models.SET: 传一个SET值或者回调函数值
    models.SET_NULL: 删除置空 父表记录被删除子表记录设置成NULL 同时需要指定null=True blank=True
    models.SET_DEFAULT: 当父表字段被删除的时候我们给子表字段设置一个默认值 用default参数指定值
    models.DO_NOTHING: 当父表被删除子表什么也不做
    """

     
    (3)关联关系
    关联关系分为三种:一对一,一对多,多对多
    1.基类

    class Teacher(models.Model):
        # 教师类
        objects = models.Manager()
    
        class Meta:
            verbose_name = "讲师信息表"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.nickname

     

    2.一对一

    其中的to和on_delete是必须参数,且要设计null和blank都要为空

    class TeacherAssistant(models.Model):
        # 助教类
        objects = models.Manager()
    
        # 外键关联
        # 一对一  助教和教师
        teacher = models.OneToOneField(to=Teacher, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="讲师")

     

    2.一对多
    其中的to和on_delete是必须参数,且要设计null和blank都为空

    class Course(models.Model):
        objects = models.Manager()
    
        # 外键关联
        # 一对多  一个讲师对应多个课程
        # 其中to和on_delete是必须参数
        teacher = models.ForeignKey(to=Teacher, null=True, blank=True, on_delete=models.CASCADE, verbose_name='课程讲师')

     

    3.多对多
    其中的to是必须参数

    class Student(models.Model):
        # 学生类
        objects = models.Manager()
    
        # 外键关联
        # 多对多 学生和课程
        course = models.ManyToManyField(to=Course, verbose_name='课程信息')

     

    (4)自关联
    利用自关联的特性构建一个类似于省市县的方法
    关联的时候可以使用‘self’或者是模型名

    class AddressInfo(models.Model):
        address = models.CharField(max_length=200, null=True, blank=True, verbose_name='地址')
        pid = models.ForeignKey('self', models.CASCADE, null=True, blank=True, verbose_name='自关联')
        # pid = models.ForeignKey('AddressInfo', null=True, blank=True, verbose_name='自关联')
    
        def __str__(self):
            return self.address

     
    三、元数据
    文档地址:https://docs.djangoproject.com/en/2.2/ref/models/options/
    设置数据库的表名等信息,对数据进行一个操作等
    一些meta中的实例,官网有更多的字段介绍和更加详细的字段信息

    class AddressInfo(models.Model):
        class Meta:
            ordering = ['pid']  # 指定按照什么 字段进行排序:-pid 是降序 没有-表示升序 添加字段的顺序表示排序的先后结果
            verbose_name = '省市县'  # 设置成一个直观的名字在admin中
            verbose_name_plural = verbose_name  # 设置成复数
            abstract = True  # 不生成数据表 作为其他类的基类
            permissions = [('定义好的权限', '给权限的说明'), ]  # 二元的列表或者是元组
            managed = False  # 是否按照Django既定的模型类管理 比如是否创建数据表
            unique_together = []  # 联合唯一键, 可以使用一元列表:只使用一组字段作为约束条件 二元列表:[[], []]
            db_table = 'address'  # 修改数据库的表名
            app_label = 'app_name'  # 定义模型类属于哪一个应用, 在app没有添加到setting的配置环境中
            db_tablespace = 'db_tablespace_name'  # 定义数据库表空间的名字

     

    四、Django的数据表
    (1)models生成流程
    1.数据表的代码

    class Teacher(models.Model):
        nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='昵称', )
        introduction = models.TextField(default="这位同学很懒,什么也没有留下来", verbose_name="简介", )
        fans = models.PositiveIntegerField(default=0, verbose_name="粉丝数")
        create_date = models.DateField(auto_now_add=True, verbose_name='创建时间', )
        update_date = models.DateField(auto_now=True, verbose_name='更新时间', )
        objects = models.Manager()
    
        class Meta:
            verbose_name = "讲师信息表"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.nickname
    
    
    class Course(models.Model):
        title = models.CharField(max_length=100, primary_key=True, db_index=True, verbose_name="课程名")
        course_type = models.CharField(choices=((0, '其他'), (1, "实战课"), (2, "免费课程")), max_length=1, default=0, verbose_name="课程类型")
        price = models.PositiveSmallIntegerField(verbose_name="价格")
        volume = models.BigIntegerField(verbose_name="销量")
        online = models.DateField(verbose_name="上线时间")
        create_date = models.DateField(auto_now_add=True, verbose_name='创建时间', )  # 系统自己添加
        update_date = models.DateField(auto_now=True, verbose_name='更新时间', )  # 系统自己添加
        objects = models.Manager()
    
        # 外键关联
        # 一对多  一个讲师对应多个课程
        teacher = models.ForeignKey(to=Teacher, null=True, blank=True, on_delete=models.CASCADE, verbose_name='课程讲师')
    
        class Meta:
            verbose_name = "课程信息表"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            # _get_FIELD_display可以展示Filed的类型
            return f"{self._get_FIELD_display(self.course_type)}-{self.title}"
    
    
    class Student(models.Model):
        nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='昵称', )
        age = models.PositiveSmallIntegerField(verbose_name="年龄")
        gender = models.CharField(choices=((1, ""), (2, ""), (0, "保密")), max_length=1, default=0, verbose_name="性别")
        study_time = models.PositiveIntegerField(default=0, verbose_name="学习时长(h)")
        create_date = models.DateField(auto_now_add=True, verbose_name='创建时间', )
        update_date = models.DateField(auto_now=True, verbose_name='更新时间', )
        objects = models.Manager()
    
        # 外键关联
        # 多对多 学生和课程
        course = models.ManyToManyField(to=Course, verbose_name='课程信息')
    
        class Meta:
            verbose_name = "学生信息表"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.nickname
    
    
    class TeacherAssistant(models.Model):
        nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='昵称', )
        hobby = models.CharField(max_length=30, null=True, blank=True, verbose_name='爱好', )
        create_date = models.DateField(auto_now_add=True, verbose_name='创建时间', )
        update_date = models.DateField(auto_now=True, verbose_name='更新时间', )
        objects = models.Manager()
    
        # 外键关联
        # 一对一
        teacher = models.OneToOneField(to=Teacher, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="讲师")
    
        class Meta:
            verbose_name = "讲师助手信息表"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.nickname
    View Code

     

    2.在对应的应用的migration中生成对应的migrations文件
    通过使用指令:【python manage.py makemigrations】完成数据的迁移,在对应的APP下面的migrations里面生成迁移数据日志


    3.在django_migrations下面的生成记录

    通过指令:【python manage.py migrate】完成数据的建表信息,将migrations里面的数据日志转成数据库语言存入数据库中

     

    4.在数据库中生成的数据表

     
    5.删除数据表
    因此再删除的时候按照上面的四步就可以删除一个models类

    (2)导入数据
    1.Django-shell
    使用【python manage.py shell】进入到命令行,导入对应的类创建对象完成数据的保存,【from [appname].models import [模板类]】

     

    2.脚本
    按照sys、os——>配置环境文件——>导入Django——>导入数据表.严格按照这个顺序导入数据信息,否则就会报错
    其中settings前面的是项目的名字
    参考blog:https://blog.csdn.net/qq_40999403/article/details/80694545

    # -*- coding:utf-8 -*-
    # __author__ == pzq
    # @email: 1427655779@qq.co
    
    import os
    import sys
    import random
    from datetime import date
    
    # 将django项目根目录加入环境变量
    parent_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    sys.path.append(parent_path)
    
    # 引入django配置文件
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "film.settings")
    # 启动django
    import django
    
    django.setup()
    
    from index.models import Student, Course, TeacherAssistant, Teacher
    
    
    def import_data():
        # 使用Django ORM导入数据
        # 讲师数据 create()
        Teacher.objects.create(nickname='Jack', introduction="Python工程师", fans=random.randint(500, 1000))
        Teacher.objects.create(nickname="Jerry", introduction="Java工程师", fans=random.randint(200, 800))
        Teacher.objects.create(nickname="Peter", introduction="PHP工程师", fans=random.randint(400, 700))
        Teacher.objects.create(nickname="Kate", introduction="C++工程师", fans=random.randint(100, 400))
    
        # 课程数据 bulk_create() 批量导入数据
        # 外键的连接通过对象
        Course.objects.bulk_create([Course(title=f"python入门课程{i}", course_type=random.choice((0, 1, 2)), price=random.randint(100, 1000),
                                           volume=random.randint(1000, 10000), online=date(random.randint(2010, 2019), random.randint(1, 12), random.randint(1, 28)),
                                           teacher=Teacher.objects.get(nickname="Jack"))
                                    for i in range(1, 4)])
    
        Course.objects.bulk_create([Course(title=f"Java入门课程{i}", course_type=random.choice((0, 1, 2)), price=random.randint(100, 1000),
                                           volume=random.randint(2000, 9000), online=date(random.randint(2010, 2019), random.randint(1, 12), random.randint(1, 28)),
                                           teacher=Teacher.objects.get(nickname="Jerry"))
                                    for i in range(1, 5)])
    
        Course.objects.bulk_create([Course(title=f"PHP进阶课程{i}", course_type=random.choice((0, 1, 2)), price=random.randint(100, 1000),
                                           volume=random.randint(1000, 4000), online=date(random.randint(2010, 2019), random.randint(1, 12), random.randint(1, 28)),
                                           teacher=Teacher.objects.get(nickname="Peter"))
                                    for i in range(1, 3)])
    
        Course.objects.bulk_create([Course(title=f"C++高阶课程{i}", course_type=random.choice((0, 1, 2)), price=random.randint(100, 1000),
                                           volume=random.randint(1000, 2000), online=date(random.randint(2010, 2019), random.randint(1, 12), random.randint(1, 28)),
                                           teacher=Teacher.objects.get(nickname="Kate"))
                                    for i in range(1, 4)])
    
        # 学生数据
        # update_or_create()  先通过nickname现在数据库中找寻这个数据  如果存在就update如果不存在就create
        # 把主键或者唯一键放在外面 把其他参数放在里面
        Student.objects.update_or_create(nickname="A同学", defaults={"age": random.randint(18, 28),
                                                                   "gender": random.choice((0, 1, 2)),
                                                                   "study_time": random.randint(1000, 2000)})
    
        Student.objects.update_or_create(nickname="B同学", defaults={"age": random.randint(18, 28),
                                                                   "gender": random.choice((0, 1, 2)),
                                                                   "study_time": random.randint(1000, 2000)})
    
        Student.objects.update_or_create(nickname="C同学", defaults={"age": random.randint(18, 28),
                                                                   "gender": random.choice((0, 1, 2)),
                                                                   "study_time": random.randint(1000, 2000)})
    
        Student.objects.update_or_create(nickname="D同学", defaults={"age": random.randint(18, 28),
                                                                   "gender": random.choice((0, 1, 2)),
                                                                   "study_time": random.randint(1000, 2000)})
    
        # 接下来添加外键字段
        # 正向添加 pk可以代替主键查找  子表关联到父表
        # 销量大于等于1000的课程
        Student.objects.get(nickname="A同学").course.add(*Course.objects.filter(volume__gte=1000))
        # 销量大于5000的课程
        Student.objects.get(nickname="B同学").course.add(*Course.objects.filter(volume__gt=5000))
        # 反向添加  通过课程关联到学生
        # 学习时间大于等于500小时的同学
        Course.objects.get(title="python入门课程1").student_set.add(*Student.objects.filter(study_time__gte=1500))
        # 学习时间小于等于500小时的同学
        Course.objects.get(title="python入门课程2").student_set.add(*Student.objects.filter(study_time__lte=1500))
    
        # 助教数据 get_or_create() 先通过nickname的关键字或者是主键进行查找 如果有就获取没有就创建
        TeacherAssistant.objects.update_or_create(nickname="助教1", defaults={"hobby": "慕课网学习", "teacher": Teacher.objects.get(nickname="Jack")})
        TeacherAssistant.objects.update_or_create(nickname="助教2", defaults={"hobby": "中国Mooc学习", "teacher": Teacher.objects.get(nickname="Jerry")})
        TeacherAssistant.objects.update_or_create(nickname="助教3", defaults={"hobby": "程序员客栈", "teacher": Teacher.objects.get(nickname="Peter")})
        TeacherAssistant.objects.update_or_create(nickname="助教4", defaults={"hobby": "牛客网", "teacher": Teacher.objects.get(nickname="Kate")})
    
        return True
    
    
    if __name__ == '__main__':
        try:
            if import_data():
                print("数据导入成功!")
        except Exception as AddError:
            print(AddError)
    View Code

     

    3.fixtures  Django serialization ——>  model  保存到数据库
    使用指令【python manage.py dumpdata > film.json】输出数据库文件


    使用指令【python manage.py loaddata film.json】输入数据到数据库

     

    4.通过数据库层面来实现
    导入SQL文件等

    (3)导出数据
    1.mange.py dumpdata > [文件名]
    2.使用pycharm或者是Navicat等数据工具来导出
    3.使用数据库层面:MySQL  dumpdata来实现

    五、models API
    queryset文档:https://docs.djangoproject.com/en/2.2/ref/models/querysets/
    (1)查询介绍

    def start(request):
        """
        int类型的操作函数:
        gte:大于等于
        exact:等于
        gt:大于
        in:在某某之内
        isnull:是否为空
        lt:小于
        lte:小于等于
        range:在什么范围内
        字符型更多:其中i是忽略大小写敏感
        """
        # 1.查询 检索 过滤
        # 返回的是对象
        teacher = Teacher.objects.filter(fans__gte=500)  # 是个query集 给字段匹配数据的时候一定要用双下划线
        # 其中pk是主键 在这里就是nickname的关键字
        t1 = Teacher.objects.get(pk="Jack")  # get只能返回一条结果 所有采取主键或者是唯一键
        t2 = Teacher.objects.all()  # 查询所有数据 返回所有数据的对象集
        # # 2.字段匹配大小写敏感
        t3 = Teacher.objects.filter(pk__icontains="A")  # 有很多可以去查看一下官网
        # # 3.结果切片  排序 链式查询
        # 切片
        t3_1 = Teacher.objects.all().order_by('-fans')[1:]
        # 排序
        t4 = Teacher.objects.all().order_by('-fans')  # -代表降序 按照老师的粉丝数进行排序
        t4_1 = Teacher.objects.all().order_by('fans')  # 默认升序
        # # 链式查询
        t5 = Teacher.objects.filter(fans__gte=500).order_by('fans')  # 先获取一个字段的属性 在对获取的数据集在采取升序排序
        t6 = Teacher.objects.filter(fans__gte=500).order_by('-fans')  # 先获取一个字段的属性 在对获取的数据集在采取降序排序
        # 4.查询原生sql语句 通过query进行查询
        print(f"我是查询语句{str(t6.query)}")
        return render(request, 'learn_set.html')
    View Code

     

    (2)返回新的queryset的API

    def start(request):
    """  查询介绍  返回新的 Query API  """
        # 1.all()  filter()  order_by():排序  exclude():除了xx元素以外  reverse():反向排序  distinct():去重
        # 可以用pk代替关键字  exclude除去含有关键字的信息
        st_0 = Student.objects.all().exclude(pk="A同学")
        # print(f"我是exclude:{st_0}")
        # 使用reverse的时候可以在Meta中用ordering指定排序的字段 多个ordering的时候取第一个 默认按照关键字的顺序输出
        st_0_1 = Student.objects.reverse()
        # print(f"我是reverse:{st_0_1}")
    
        # 2.extra():给字段取别名   defer():排除一些字段   only():选择一些字段
        # extra(): extra(select={"[要取的别名]": "[原来字段名]"})
        st_1 = Student.objects.all().extra(select={"name": "nickname"})
        # for i in st_1:
        #     print(f"我是extra:{i.name}")
        st_2 = Student.objects.all().only('nickname', 'age')
        # print(f"我是only_query:{str(st_2.query)}")
    
        # 3.values():字典 values_list():元组  获取字典或者是元组形式的queryset
        # values() 输出的是dict类型的
        st_3_0 = TeacherAssistant.objects.values('nickname', 'hobby')
        # print(f"我是values:{st_3_0}")
        # values_list() 输出的是元组类型的数据
        st_3_1 = TeacherAssistant.objects.values_list('nickname', flat=True)  # flat:将单个字段的数据直接放到列表里面  只限于获取单个数据的信息
        # print(f"我是values_list:{st_3_1}")
    
        # 4.根据时间和日期获取查询集  dates:年月日  datetimes年月日时分秒查询字段多一点有时分秒  使用什么查询方式取决于定义字段的类型
        # datetimes('[查询时间的字段]', 'month', order='DESC')
        st_4 = Course.objects.dates('online', 'year', order='DESC')  # ASC 升序排列(默认)  DESC降序排列
        # print(f"我是dates:{st_4}")
    
        # 5.集合的运算  union():并集   intersection():交集   difference():差集
        s_1 = Student.objects.filter(study_time__gte=1600)  # 大于等于1500
        s_2 = Student.objects.filter(study_time__lte=1500)  # 小于等于1600
        # print(f"我是union:{s_1.union(s_2)}")  # 只支持取并集
        # print(f"我是intersection:{s_1.intersection(s_2)}")  # 数据库不支持
        # print(f"我是difference:{s_1.difference(s_2)}")  # 数据库不支持
    
        # 6.优化查询api  select_related() 一对一 多对一的优化查询   prefetch_related() 一对多 多对多的优化查询
        # select_related()
        # 通过课程获取讲师信息 查询相关信息通过外接字段进行连接
        c_1 = Course.objects.all().select_related('teacher')
        for c in c_1:
            print(f"课程信息:{c.title}--{c.teacher.nickname}--{c.teacher.fans}")
        # prefetch_related() 多对多
        s_1 = Student.objects.filter(age__lte=30).prefetch_related('course')
        for s in s_1:
            for i in s.course.all():  # 获取到的是managerelmanage的对象
                print(f"{s.nickname}--{i.title}")  # 输出课程的信息
        # 反向查询:根据父表查询子表
        # 通过在数据段的对应关系  [字表的表名]_set可以替换为related_name的值
        t_1 = Teacher.objects.get(nickname='Jack').teach.all()
        print(f"我是反向查询{t_1}")
    
        # 7.annotate() 使用聚合计数、求和、平均数、raw()、执行原生的SQL
        # 求和 sum_1 = Course.objects.values('[处理表单]').annotate(vol=Sum('[处理字段]'))
        sum_1 = Course.objects.values('teacher').annotate(vol=Sum('volume'))
        print(f"我是求和:{sum_1}")
        # 平均值
        ave_1 = Student.objects.values('course').annotate(time=Avg('study_time'))
        print(f"我是求平均值:{ave_1}")
        # row可以写原生数据语句 里面执行原生的SQL语句
        # 参考文档
        # https://docs.djangoproject.com/en/2.2/topics/db/sql/
    View Code

     

    (3)不返回新的query的API

    def start(request):
    """  不返回查询集的API """
        # 参考文档:https://docs.djangoproject.com/en/2.2/ref/models/querysets/#raw
        # 1.获取对象 get() get_or_create() first() last()  latest()  earliest()  in_bulk()
        # get() 获取对象
        # get_or_create() 有数据就通过get获取没有就创建数据
        # first()  # 第一条记录
        # print(f"我是first:{Course.objects.first()}")
        # last()  # 最后一条记录
        # print(f"我是last:{Course.objects.last()}")
        # latest()  # 最近的记录 需要在模型类里面设置 get_latest_by = [创建的字段] 代表根据创建的字段进行排序
        # 也可以在排序的时候自己指定 更加方便我们自己的操作
        # print(f"我是latest{Course.objects.latest('online')}")
        # earliest() # 最早的记录
        # print(f"我是earliest{Course.objects.earliest('update_date')}")
        # in_bulk() 批量返回对象 根据主键的值传递一个列表 列表中传递主键的值
        # print(Course.objects.in_bulk(['Java入门课程1', 'Java入门课程2', 'python入门课程2']))
        # 2.创建对象  create():创建对象  bulk_create():批量创建对象  create_or_update():如果没有就创建有就更新
        # bulk_create:给函数创建一个列表
        # 3.更新对象 update():更新  update_or_create():更新或创建
        # update()
        # print(f"我是更新前的价格:{Course.objects.get(title='C++高阶课程1').price}")
        # Course.objects.filter(title="C++高阶课程1").update(price=568)
        # print(f"我是更新后的价格:{Course.objects.get(title='C++高阶课程1').price}")
        # 4.删除对象 delete():使用filter过滤
        # print(Course.objects.filter(title="test_1").delete())
        # 5.其他操作 exist():是否存在  count():统计个数  aggregate():聚合
        # exist()
        # print(Course.objects.filter(title="test_1").exists())
        # print(Course.objects.filter(title="PHP进阶课程2").exists())
        # count()记录数据表中的数据个数
        # print(Course.objects.count())
        # annotate():和value配合使用 对分组结果进行排序  aggregate():对数据库中的数据结果进行处理
        # print(Course.objects.aggregate(Max('price'), Min('price'), Avg('price'), Sum('volume')))
        return render(request, 'learn_set.html')
    View Code

     
    (4)自定义聚类查询
    1.自定义查询方法
    在individual.py中加入以下代码

    from django.db import models
    
    
    class Concat(models.Aggregate):
        """ORM用来分组显示其他字段 相当于group_concat"""
        function = 'GROUP_CONCAT'
        template = '%(function)s(%(distinct)s%(expressions)s)'
    
        def __init__(self, expression, distinct=False, **extra):
            super(Concat, self).__init__(
                expression,
                distinct='DISTINCT ' if distinct else '',
                output_field=models.CharField(),
                **extra)

     
    2.引用

    在views.py中的引用

    from .individual import Concat
    def start(request):
    """ 自定义聚合查询 """
        # 这个title对应查询结果中的key Concat里面的才是我们需要查询的字段
        course = Course.objects.values('teacher').annotate(title=Concat('title'))
        for c in course:
            print(c)
        return render(request, 'learn_set.html')

     
    (5)F对象查询
    官方文档:https://docs.djangoproject.com/en/2.2/ref/models/expressions/#django.db.models.F

    def start(request):
    """ F查询 """
        # 操作字段数据或者是将一个字段与另一个字段进行比较
        # # 将所有的价格减11
        # Course.objects.update(price=F('price') - 11)
        # # 获取销量大于价格10倍的字段
        # course = Course.objects.filter(volume__gte=F('price') * 10)
        # for c in course:
        #     print(f"{c.title}--{c.price}--{c.volume}")
        return render(request, 'learn_set.html')


    (6)Q对象查询
    官方文档:https://docs.djangoproject.com/en/2.2/ref/models/querysets/#q-objects

    def start(request):
        """ Q对象结合 &:and |:or :not 实现复杂的查询 """
        # 查询所有Java课程  并且销量大于等于5000
        print(Course.objects.filter(Q(title__icontains='java') & Q(volume__gte=5000)))
        # 查询所有Python语言或者是销量小于2000的课程
        print(Course.objects.filter(Q(title__icontains='python') | Q(volume__lte=2000)))
        return render(request, 'learn_set.html')

    (7)模型类实例:

    class Teacher(models.Model):
        nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='昵称', )
        introduction = models.TextField(default="这位同学很懒,什么也没有留下来", verbose_name="简介", )
        fans = models.PositiveIntegerField(default=0, verbose_name="粉丝数")
        create_date = models.DateField(auto_now_add=True, verbose_name='创建时间', )
        update_date = models.DateField(auto_now=True, verbose_name='更新时间', )
        # 每一个非抽象model类必须Manager添加一个实例
        objects = models.Manager()
    
        class Meta:
            verbose_name = "讲师信息表"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.nickname
    
    
    class Course(models.Model):
        title = models.CharField(max_length=100, primary_key=True, db_index=True, verbose_name="课程名")
        course_type = models.CharField(choices=((0, '其他'), (1, "实战课"), (2, "免费课程")), max_length=1, default=0, verbose_name="课程类型")
        price = models.PositiveSmallIntegerField(verbose_name="价格")
        volume = models.BigIntegerField(verbose_name="销量")
        online = models.DateField(verbose_name="上线时间")
        create_date = models.DateField(auto_now_add=True, verbose_name='创建时间', )  # 系统自己添加
        update_date = models.DateField(auto_now=True, verbose_name='更新时间', )  # 系统自己添加
        objects = models.Manager()
    
        # 外键关联
        # 多对一  多个课程对应一个讲师
        teacher = models.ForeignKey(to=Teacher, null=True, blank=True, on_delete=models.CASCADE, verbose_name='课程讲师', related_name='teach')
    
        class Meta:
            verbose_name = "课程信息表"
            verbose_name_plural = verbose_name
            # 根据创建的字段进行排序  方便latest和earliest进行排序  也可以在排序时指定
            # get_latest_by = 'online'
    
        def __str__(self):
            # get_[要展示的字段]_display()就可以输出了  如2--python入门课程1>,
            return f"{self.get_course_type_display()}--{self.title}"
    
    
    class Student(models.Model):
        nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='昵称', )
        age = models.PositiveSmallIntegerField(verbose_name="年龄")
        gender = models.CharField(choices=((1, ""), (2, ""), (0, "保密")), max_length=1, default=0, verbose_name="性别")
        study_time = models.PositiveIntegerField(default=0, verbose_name="学习时长(h)")
        create_date = models.DateField(auto_now_add=True, verbose_name='创建时间', )
        update_date = models.DateField(auto_now=True, verbose_name='更新时间', )
        objects = models.Manager()
    
        # 外键关联
        # 多对多 学生和课程
        course = models.ManyToManyField(to=Course, verbose_name='课程信息')
    
        class Meta:
            # 指定多个时  按第一个进行排序
            # 不指定根据关键字的顺序进行排序  如在数据表中添加的数据顺序
            ordering = ['study_time']
            verbose_name = "学生信息表"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.nickname
    
    
    class TeacherAssistant(models.Model):
        nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='昵称', )
        hobby = models.CharField(max_length=30, null=True, blank=True, verbose_name='爱好', )
        create_date = models.DateField(auto_now_add=True, verbose_name='创建时间', )
        update_date = models.DateField(auto_now=True, verbose_name='更新时间', )
        objects = models.Manager()
    
        # 外键关联
        # 一对一  如果on_delete置空就要将null, blank都设置为空
        teacher = models.OneToOneField(to=Teacher, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="讲师")
    
        class Meta:
            verbose_name = "讲师助手信息表"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.nickname
    View Code

     六、总结
    本篇blog简单的介绍了orm的内容,也是Django后端内容中最为重要的一个部分,其他详情请参考Django的官方文档

     

  • 相关阅读:
    DTOJ #3328. 开箱子(unboxing)
    dtoi4649 光明
    dtoi4539「TJOI / HEOI2016」序列
    dtoi3031 交错和查询 (sum)
    dtoi4375「BJOI2019」删数
    dtoi4266 exchange
    dtoi4680 红黑兔
    dtoi1363 楼房重建 (rebuild)
    dtoi1927 [ONTAK2010]Peaks加强版
    dtoi4538 「TJOI / HEOI2016」排序
  • 原文地址:https://www.cnblogs.com/future-dream/p/10604600.html
Copyright © 2020-2023  润新知