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'))
原文地址:https://www.cnblogs.com/caoyu080202201/p/12992647.html