一、测试脚本:只是需要测试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'))