• Django之模型层


    一、测试脚本:只是需要测试Django项目中某个py文件的内容,可以不必通过前端,直接在测试脚本里面运行即可。

      1、脚本代码可以app下自带的tests.py里面,也可以在主文件夹下新建任意署名的py文件,如mytest.py。

      2、准备测试环境,在测试脚本的开头写上如下几行语句(部分可以拷贝自manage.py):

    import os
    
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tproject0530.settings")
        import django
    
        django.setup()

      3、准备工作完成后,可以在"main"下面写测试语句了,注意,需要导入的模块,也必须在"main"下面书写。

    二、创建表(模型层)

    class Enemy(models.Model):
        name = models.CharField(max_length=32, verbose_name='名号')
        charge = models.CharField(max_length=32, verbose_name='罪名')
        reward = models.BigIntegerField(verbose_name='赏金')
        index = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='危险指数')
        # 邮箱格式,本质是 varchar(254)
        email = models.EmailField(verbose_name='恶徒邮箱')
        # 初建时间,固定值,后续修改该条记录不会影响这个时间
        first_time = models.DateField(auto_now_add=True, verbose_name='登记时间')
        # 更新时间,动态值,每次修改记录会更新为当时的时间
        update_time = models.DateField(auto_now=True, verbose_name='最后更新时间')
    
    
    class Hunter(models.Model):
        code_name = models.CharField(max_length=32, verbose_name='代号')
        weapon = models.CharField(max_length=32, verbose_name='武器')
        skill = models.CharField(max_length=32, verbose_name='必杀技')
        level = models.ForeignKey(to='Level', verbose_name='猎赏者等级')
        task = models.ManyToManyField(to='Task', verbose_name='已接任务编号')
        more_info = models.OneToOneField(to='HunterMoreInfo', verbose_name='隐藏信息')
    
    
    class Level(models.Model):
        name = models.CharField(max_length=32, verbose_name='等级名称')
        right = models.CharField(max_length=32, verbose_name='处刑权限')
    
    
    class Task(models.Model):
        area = models.CharField(max_length=32, verbose_name='任务区域')
        time_limit = models.IntegerField(verbose_name='任务时限')
    
    
    class HunterMoreInfo(models.Model):
        real_name = models.CharField(max_length=32, verbose_name='真实姓名')
        cover_identity = models.CharField(max_length=32, verbose_name='伪装身份')

    三、单表的增/改/删

    # 通过 create 直接新建,同时也会返回记录对象
        enemy_obj_1 = models.Enemy.objects.create(
            name='"萌新大佬"新哥',
            charge='资深小白,在线求带,会唱歌,声音巨嗲的那种',
            reward=10,
            index=0.03,
            email='xinxin@oldboy.com'
        )
        # 先生成记录对象,再通过 save 同步到数据库
        enemy_obj_2 = models.Enemy(
            name='"人键合一"刘老师',
            charge='内容过多,无法展示',
            reward=80000000,
            index=9.00,
            email='liuDSBoy@oldboy.com'
        )
        enemy_obj_2.save()
        # 用filter查找,无论条件是否唯一匹配,拿到的结果都是记录对象集
        # 若需要再拿出单个记录对象,需要使用 first 等方法
        # 通过 update 直接修改,只有记录对象集有该方法,单个记录对象无法使用
        models.Enemy.objects.filter(id=1).update(reward=50)
        # 筛选条件 pk 即主键的意思,比 id 适用性更强
        enemy_obj_3 = models.Enemy.objects.filter(pk=2).first()
        # 先修改记录对象的属性
        enemy_obj_3.index = 9.50
        # 在通过 save 同步到数据库
        enemy_obj_3.save()
        # 先新建三条测试用记录
        models.Enemy.objects.create(
            name='ttt',
            charge='ttt',
            reward=111,
            index=111,
            email='111@111.com'
        )
        models.Enemy.objects.create(
            name='ddd',
            charge='ddd',
            reward=222,
            index=222,
            email='222@222.com'
        )
        models.Enemy.objects.create(
            name='vvv',
            charge='vvv',
            reward=333,
            index=333,
            email='333@333.com'
        )
        # 通过 delete 直接删除
        models.Enemy.objects.filter(name='ttt').delete()
        # delete 方法可用于记录对象集,也可以用于单个记录对象
        models.Enemy.objects.filter(name='ddd').first().delete()
        # pk 即代表主键,比 id 适用性更强
        models.Enemy.objects.filter(pk=10).first().delete()

    四、单表查询相关

      1、查看orm语句对应的sql语句的方法:

        ①无需额外配置:

        # 通过 query 查看,只能用于记录对象集
        queryset_obj_1 = models.Enemy.objects.values('name', 'index')
        print(queryset_obj_1.query)

        ②在setting.py里面如下配置,所有操作会自动打印sql语句:

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level': 'DEBUG',
            },
        }
    }

      2、常用方法:

        # 查看所有,结果是记录对象集
        print(models.Enemy.objects.all())
        # 按筛选条件查看,结果是记录对象集
        print(models.Enemy.objects.filter(reward=50))
        # 直接查看单个记录对象,条件不存在会报错,能匹配的对象超过1个也会报错
        print(models.Enemy.objects.get(pk=1))
        # 查看记录对象集的第一个记录对象
        print(models.Enemy.objects.all().first())
        print(models.Enemy.objects.filter(reward=50).first())
        # 与 first 同理,查看最后一个
        print(models.Enemy.objects.all().last())
        # 查看指定字段的值,结果是字典式记录对象集
        # values 只能用于记录对象集,不能用于单个记录对象
        print(models.Enemy.objects.all().values('name'))
        print(models.Enemy.objects.filter(reward=80000000).values('pk', 'id'))
        # 查看指定字段的值,结果是元祖式记录对象集
        # values_list 只能用于记录对象集,不能用于单个记录对象
        print(models.Enemy.objects.all().values_list('name', 'reward'))
        # 什么都不写,查看记录对象组成的单个表对象,可以用记录对象集的方法
        print(models.Enemy.objects)
        # 按照指定字段去重,结果与前面方法的格式一致
        # 如果不指定字段,则会因为主键唯一,一定没有重复可去
        print(models.Enemy.objects.values('reward').distinct())
        print(models.Enemy.objects.values_list('reward').distinct())
        print(models.Enemy.objects.values_list().distinct())  # 有主键,一定没有重复
        # 按照指定字段排序,结果为记录对象集,默认降序
        print(models.Enemy.objects.order_by('index').values_list('index'))
        # 字段名加负号,则改为升序
        print(models.Enemy.objects.order_by('-index').values_list('index'))
        # 反转,对排序过的结果才有效果,结果与前面方法的格式一致
        print(models.Enemy.objects.values_list('reward').order_by('-index').reverse())
        # 统计个数,可用于集,也可以单个对象(1个也要数一下)
        print(models.Enemy.objects.count())
        print(models.Enemy.objects.all().values('name').count())
        print(models.Enemy.objects.filter(pk=1).count())
        # 反过滤,排除某条件
        print(models.Enemy.objects.all().values_list('name').exclude(reward=80000000))
        # 判断是否存在,返回布尔值,只能用于集
        print(models.Enemy.objects.filter(pk=1).exists())
        print(models.Enemy.objects.filter(pk=1).values('reward').exists())

      3、双下划线系列:

        # 大于
        print(models.Enemy.objects.filter(index__gt=5).count())
        # 小于
        print(models.Enemy.objects.filter(reward__lt=100).values_list('name'))
        # 大于等于/小于等于
        print(models.Enemy.objects.filter(pk__gte=11).values_list('name'))
        print(models.Enemy.objects.filter(id__lte=2).values_list('name'))
        # 在某几个之中
        print(models.Enemy.objects.filter(pk__in=[1, 2, 11]).values_list('name'))
        # 在某范围内,包含头尾
        print(models.Enemy.objects.filter(id__range=[2, 13]).values_list('name'))
        # 值内包含某字符,相当于模糊匹配
        print(models.Enemy.objects.filter(email__contains='Old').values_list('name'))
        # 可以声明为不区分大小写
        print(models.Enemy.objects.filter(email__icontains='Old').values_list('name'))
        # 头/尾是某字符,也分是否区别大小写
        print(models.Enemy.objects.filter(email__startswith='Xin').values_list('name'))
        print(models.Enemy.objects.filter(email__istartswith='Xin').values_list('name'))
        print(models.Enemy.objects.filter(email__endswith='Com').values_list('name'))
        print(models.Enemy.objects.filter(email__iendswith='Com').values_list('name'))
        # 时间相关
        print(models.Enemy.objects.filter(first_time__year=2020).values_list('name'))
        print(models.Enemy.objects.filter(update_time__month=5).values_list('name'))

    五、多表增/改/删

      1、新建带有外键的记录:

        models.Hunter.objects.create(
            code_name='kevin',
            weapon='<反曲弓>绿原之怒',
            skill='单眼皮锁定',
            level_id=3,  # 通过外键关联记录的id
            more_info_id=1,  # 通过外键关联记录的id
        )
        level_obj_1 = models.Level.objects.filter(pk=4).first()
        hunter_more_info_obj_1 = models.HunterMoreInfo.objects.filter(pk=2).first()
        models.Hunter.objects.create(
            code_name='tank',
            weapon='<连弩>光速之星',
            skill='急速射击改',
            level=level_obj_1,  # 通过外键关联记录对象本身
            more_info=hunter_more_info_obj_1,  # 通过外键关联记录对象本身
        )

      2、多对多关系的绑定:

        hunter_obj_1 = models.Hunter.objects.filter(pk=1).first()
        # 给持有外键一方的记录对象绑定另一方的 id,直接写值即可
        hunter_obj_1.task.add(2)
        # 也可以以此写多个 id
        hunter_obj_1.task.add(3, 4)
        hunter_obj_2 = models.Hunter.objects.filter(pk=2).first()
        task_obj_1 = models.Task.objects.filter(pk=2).first()
        task_obj_2 = models.Task.objects.filter(pk=5).first()
        task_obj_3 = models.Task.objects.filter(pk=6).first()
        # 也可以直接绑定记录对象,同样支持一次多个
        hunter_obj_2.task.add(task_obj_1)
        hunter_obj_2.task.add(task_obj_2, task_obj_3)

      3、一对多/一对一外键的修改:

        # 通过 update 修改,同样不能用于单个记录对象,只能用于集,指定新的关联记录的 id
        models.Hunter.objects.filter(pk=2).update(level=2)
        # 也可以指定新的 外键关联记录对象本身
        level_obj_2 = models.Level.objects.filter(pk=3).first()
        hunter_obj_3 = models.Hunter.objects.filter(pk=2).update(level=level_obj_2)
        # 一对一同理,演示 save方法
        hunter_obj_4 = models.Hunter.objects.filter(pk=2).first()
        hunter_obj_4.more_info_id = 7
        hunter_obj_4.save()
        hunter_obj_5 = models.Hunter.objects.filter(pk=2).first()
        hunter_more_info_obj_2 = models.HunterMoreInfo.objects.filter(pk=2).first()
        hunter_obj_5.more_info = hunter_more_info_obj_2
        hunter_obj_5.save()

      4、多对多关系修改:

        hunter_obj_6 = models.Hunter.objects.filter(pk=1).first()
        # 修改方案必须为多元素类型,放关联记录的 id,若修改方案中有与原方案相同的,则在关系表中不会重写那一行
        hunter_obj_6.task.set([2, 3, 5])
        task_obj_4 = models.Task.objects.filter(pk=2).first()
        task_obj_5 = models.Task.objects.filter(pk=3).first()
        task_obj_6 = models.Task.objects.filter(pk=4).first()
        # 也可以放关联记录对象本身,也可以放一个元素
        hunter_obj_7 = models.Hunter.objects.filter(pk=1).first()
        hunter_obj_7.task.set([task_obj_4])
        hunter_obj_7.task.set([task_obj_4, task_obj_5, task_obj_6])

      5、一对多/一对一外键的删除,级联更新/级联删除:Django1.0+默认级联更新/级联删除,在此机制下,关联表的某记录修改或删除,外键所持表的对应记录的外键字段也会相应修改或删除。

      6、多对多关系的解除:

        hunter_obj_8 = models.Hunter.objects.filter(pk=1).first()
        hunter_obj_9 = models.Hunter.objects.filter(pk=2).first()
        hunter_obj_10 = models.Hunter.objects.filter(pk=6).first()
        task_obj_7 = models.Task.objects.filter(pk=5).first()
        task_obj_8 = models.Task.objects.filter(pk=6).first()
        # 关联记录的 id
        hunter_obj_8.task.remove(2)
        # 可放多个,可放关联记录对象本身
        hunter_obj_9.task.remove(task_obj_7, task_obj_8)
        # 清除某记录的所有多对多外键
        hunter_obj_10.task.clear()

    六、多表查询相关

      1、正反向概念:

        ①从持有外键的表发起的查找就是正向查找,从关联表查到持有外键的表就是反向查找。

        ②正向查找,直接点外键字段。

        ②反向查找:

          a、一对多/多对多:持有外键表的表名小写_set。

          b、一对一:持有外键表的表名小写。

      2、当查询到另一个表时,对象可能为多个时,要加上.all(),对象一定唯一时,则不加。

      3、跨表查询的两种方式:

        ①通过<点>跨表。

        ②通过<双下划线>跨表。

      4、实例:

        # 正向,用点点的方式,查询id=3的hunter的所有task的time_limit
        hunter_obj_11 = models.Hunter.objects.filter(pk=3).first()
        print(hunter_obj_11.task.all().values_list('time_limit'))
        # 正向,用双下划线的方式,查询id=4的hunter的code_name和more_info的real_name,以及level的right
        hunter_obj_12 = models.Hunter.objects.filter(pk=4)
        print(hunter_obj_12.values_list('code_name', 'more_info__real_name', 'level__right'))
        # 反向,用点点的方式查询:
        # 一、hunter_more_info的real_name='林大炮'的hunter的weapon
        # 二、level的id=1的所有hunter的code_name
        # 三、task的area='松江区'的hunter的skill
        hunter_more_info_obj_11 = models.HunterMoreInfo.objects.filter(real_name='林大炮').first()
        print(hunter_more_info_obj_11.hunter.weapon)
        level_obj_11 = models.Level.objects.filter(pk=1).first()
        print(level_obj_11.hunter_set.all().values('code_name'))
        task_obj_11 = models.Task.objects.filter(area='松江区').first()
        print(task_obj_11.hunter_set.all().values('skill'))
        # 反向,用双下划线的方式查询:
        # 一、hunter_more_info的id=5的cover_identity,以及hunter的weapon
        # 二、level的name='特等猎赏者'的id,以及hunter的code_name
        # 三、task的time_limit=24的area,以及hunter的skill
        hunter_more_info_obj_12 = models.HunterMoreInfo.objects.filter(pk=5)
        print(hunter_more_info_obj_12.values('cover_identity', 'hunter__weapon'))
        level_obj_12 = models.Level.objects.filter(name='特等猎赏者')
        print(level_obj_12.values('pk', 'hunter__code_name'))
        task_obj_12 = models.Task.objects.filter(time_limit=24)
        print(task_obj_12.values('area', 'hunter__skill'))
        # 用双下划线的方式正向反向切换查找,查找hunter_more_info的id=1的cover_identity,以及hunter的code_name,以及level的right
        hunter_more_info_obj_13 = models.HunterMoreInfo.objects.filter(pk=1)
        print(hunter_more_info_obj_13.values('cover_identity', 'hunter__code_name', 'hunter__level__right'))
  • 相关阅读:
    MSSQl分布式查询
    欲善其事,必利其器 Librame Utility R1 实用工具包(.NET Framework 3.5)
    可复用的WPF或者Silverlight应用程序和组件设计(3)——控件级别
    Asp.Net 网站优化 数据库优化措施 使用主从库
    .NET独有的精巧泛型设计模式
    Javascript 使用 "大杂烩"
    淘宝下单高并发解决方案
    时间戳(timestamp)
    MSSQL锁机制
    maven开发过程实践
  • 原文地址:https://www.cnblogs.com/caoyu080202201/p/12992647.html
Copyright © 2020-2023  润新知