Django JSONField类型操作解析

article/2025/9/23 18:29:33

Django JSONField类型操作解析

      • 模型代码设计
      • 正向查询与反向查询解析
      • Json字段操作解析
        • 新增
        • 查询
          • Json条件查询
          • 字段条件查询
          • 跨关系查询
        • 修改
        • 删除

接口测试平台核心以Httprunner为接口用例运行框架,要将用例的数据持久化到数据库中,方便读取修改与存储,则需要按照 yaml/json 的数据结构来设计数据库。

数据库模型关系图的总体结构

请添加图片描述

执行命令 django-admin startproject AutoTpsite 创建一个项目名为 AutoTpsite 的Django项目

再执行python manage.py startapp sqtp命令创建一个名为 sqtp的应用

模型代码设计

其中,request,step和config参考HR对应部分的字段,由于其中会出现很多嵌套字段,所以1层的字段就用json数据类型来代替。

models.py下创建模型

配置config部分

class Config(models.Model):name = models.CharField('测试用例名称',max_length=128)base_url = models.CharField('IP/域名',max_length=256,null=True,blank=True) #可为空或者空白variables = models.JSONField('变量',null=True)parameters = models.JSONField('参数',null=True)export = models.JSONField('用例返回值',null=True)verify = models.BooleanField('https校验',default=False)def __str__(self):return self.name# 以 测试用例名称 对外展示

通过 models.JSONField 可指定此字段为存储类型为JSON格式。null=True 表示此字段可以为空,这个NULL指的是SQL NULL,如果想存储为JsonNULL,则可以使用 Value('null') 来实现

用例Case部分

class Case(models.Model):# 一对一关系指向配置config 关联约束选择  DO_NOTHING 不做删除,保留config = models.OneToOneField(Config,on_delete=models.DO_NOTHING)# 用例文件路径,用于后续数据的导出file_path = models.CharField('用例文件路径',max_length=1000,default='demo_case.json')def __str__(self):return self.config.name# 以 config名称(测试用例名称) 对外展示

测试用例与配置config的对应关系为 一对一 ,通过 models.OneToOneField 配置关联约束

测试步骤Step部分

class Step(models.Model):# related_name 反向查询名称 同个模型中,两个字段关联同1个模型,必须指定related_name ,且名字不能相同# 属于哪条测试用例,属于的用例被删除了,测试步骤也就没有存在的必要了 关联约束选择 CASCADE级联删除belong_case = models.ForeignKey(Case,on_delete=models.CASCADE,related_name='teststeps')# 引用的哪条测试用例,引用的用例被删除了,测试步骤可能还需要存在 关联约束选择  DO_NOTHING 不做删除,保留,或 SET_NULL 允许为nulllinked_case = models.ForeignKey(Case,on_delete=models.SET_NULL,null=True,related_name='linked_steps')name = models.CharField('测试步骤名称', max_length=128)variables = models.JSONField('变量', null=True)extract = models.JSONField('请求返回值', null=True)validate = models.JSONField('校验项', null=True)setup_hooks = models.JSONField('初始化', null=True)teardown_hooks = models.JSONField('清除', null=True)def __str__(self):return self.name# 以 测试步骤名称 对外展示

Httprunner测试框架中,测试步骤可以属于某条测试用例,一条测试用例中可能会存在多条测试用例;而测试步骤也能引用其他测试用例。

在数据存储的观点来看,测试步骤与测试用例之间的关系为 多对一 ,通过外键 ForeignKey 进行关联,但在模型的设计中,需要将这两种关联关系区分开来,所以需要有两个字段。两个字段关联同1个模型,这里需要通过related_name 反向查询名称进行区分,且名字不能相同

请求Request部分

class Request(models.Model):# 一对一关系指向测试步骤Step 关联约束选择 CASCADE级联删除step = models.OneToOneField(Step,on_delete=models.CASCADE,null=True)# method可选字段,二维元组method_choices = ((0, 'GET'),  # 参数1:保存在数据库中的值,参数2:对外显示的值(1, 'POST'),(2, 'PUT'),(3, 'DELETE'),)method = models.SmallIntegerField('请求方法',choices=method_choices,default=0)url = models.CharField('请求路径', default='/', max_length=1000)params = models.JSONField('url参数', null=True)headers = models.JSONField('请求头', null=True)cookies = models.JSONField('Cookies', null=True)data = models.JSONField('data参数', null=True)json = models.JSONField('json参数', null=True)def __str__(self):return self.url# 以 请求路径 对外展示

http请求方式通常有GET、POST、PUT、DELETE,像这种数据库存储字段的值有限定内容的时候,可以先创建一个二维元组,参数1表示保存在数据库中的值,参数2表示对外显示的值,通过choices指定创建的二维元素。数据库中只需要存0、1、2、3这些数字即可,不需要设定为CharField类型,设定为SmallIntegerField即可,这种方式可以减少数据存储的压力。

正向查询与反向查询解析

在1对1,1对多,多对多关系中都存在正向查询和反向查询,模型查询其关联的项目叫做正向查询

如多对一关系中,正向查询是多方查询单方,因为外键是定义在多方,通过模型对象的外键 即modelObj.foreigner 进行查询则为正向查询;反向查询是单方查找多方,通过模型对象的外键模型的小写_setmodelObj.foreigner_set 进行查询

在tests.py文件下进行测试

from django.test import TestCase# Create your tests here.from sqtp.models import Case,Config,Step,Requestclass TestRelatedQuery(TestCase):def setUp(self) -> None:self.config1 = Config.objects.create(name='用例1',base_url='http://127.0.0.1:8080/')self.config2 = Config.objects.create(name='用例2',base_url='http://127.0.0.1:8888/')self.case1 = Case.objects.create(config=self.config1)self.case2 = Case.objects.create(config=self.config2)def test_steps_query(self):step1 = Step.objects.create(belong_case=self.case1, name='步骤1') # 步骤1关联用例1step1.linked_case = self.case2 # 步骤1引用用例1step1.save()step2 = Step.objects.create(belong_case=self.case2, name='步骤2') # 步骤2关联用例2# 正向查询print('===========正向查询===========')print(step1.belong_case) #查看step1所属用例print(step1.linked_case)  # 查看step1引用的用例print(step2.belong_case) #查看step2所属的用例# 反向查询print('===========反向查询===========')# related_name代替 step_setprint(self.case1.teststeps.all()) # 查询用例1下面有哪些步骤print(self.case2.linked_steps.all()) # 查询用例2被哪些步骤引用

输出结果

===========正向查询===========
用例1
用例2
用例2
===========反向查询===========
<QuerySet [<Step: 步骤1>]>
<QuerySet [<Step: 步骤1>]>

外键在 Step模型 中定义,与 Case模型 进行关联,而 Case模型 与 Config模型 一对一关联。

通过Step查询关联的用例,则是正向查询

通过用例查询步骤,则是属于反向查询,正常情况下要通过模型小写_set(即step_set)进行查询,但是在Step模型 中比较特殊,两个字段关联同1个模型,所以需要用 related_name 代替 step_set

Json字段操作解析

模型中大部分字段都是json类型(Django模型 JSONField类型)存储,以Request(请求信息)模型为例,操作增删改查

在tests.py文件下进行测试

新增

from django.test import TestCase# Create your tests here.from sqtp.models import Case, Config, Step, Request
from django.db.models import Valueclass TestJsonField(TestCase):def setUp(self) -> None:print('====================新增数据======================')req1 = Request.objects.create(method=1,url='/mgr/student/',data={"name":"小明","age":16,"address":"广东广州","school":{"PrimarySchool":"实验小学","SecondarySchool":"第一中学"}})req2 = Request.objects.create(method=0,url='/api/teacher/',data={"name":"小王老师","courses":"英语","address":"广东深圳"})req3 = Request.objects.create(method=3,url='/api/delete/',data={"id":105,"display_idx":1})req = Request.objects.all()print(req)

执行命令python manage.py test sqtp.tests.TestJsonField进行测试

通过objects.create()新增数据,通过Request.objects.all()查询数据,输出结果

====================新增数据======================
<QuerySet [<Request: /mgr/student/>, <Request: /api/teacher/>, <Request: /api/delete/>]>

查询

Json条件查询
class TestJsonField(TestCase):def setUp(self) -> None:print('====================新增数据======================')req1 = Request.objects.create(method=1,url='/mgr/student/',data={"name":"小明","age":16,"address":"广东广州","school":{"PrimarySchool":"实验小学","SecondarySchool":"第一中学"}})req2 = Request.objects.create(method=0,url='/api/teacher/',data={"name":"小王老师","courses":"英语","address":"广东深圳"})req3 = Request.objects.create(method=3,url='/api/delete/',data={"id":105,"display_idx":1})req = Request.objects.all()print(req)def test_json_01(self):print('====================查询数据======================')req1 = Request.objects.all().first()print(req1)print(req1.data)  # 查询data数据内容print('====================json条件查询======================')req2 = Request.objects.filter(data__age=16)print(req2)req3 = Request.objects.filter(data__school__PrimarySchool="实验小学")print(req3)

通过Request.objects.all().first()查询出第一条数据

若想要根据json里的内容筛选数据,可以根据字段名__参数名(注意是双下划线)查询json字段里的内容,存在多层嵌套,依旧可以查询成功

输出结果

====================查询数据======================
/mgr/student/
{'name': '小明', 'age': 16, 'address': '广东广州', 'school': {'PrimarySchool': '实验小学', 'SecondarySchool': '第一中学'}}
====================json条件查询======================
<QuerySet [<Request: /mgr/student/>]>
<QuerySet [<Request: /mgr/student/>]>
字段条件查询

字段查询是指如何指定 SQL WHERE子句 的内容。它们用作 QuerySet 的 filter()、exclude() 和 get() 方法的关键字参数。 其基本格式是:field__lookuptype=value(注意其中是双下划线),默认查找类型为exact(精确匹配)。

Django的数据库API支持20多种查询类型:

字段名说明
exact精确匹配
iexact不区分大小写的精确匹配
contains包含匹配
icontains不区分大小写的包含匹配
in在…之内的匹配
gt大于
gte大于等于
lt小于
lte小于等于
startswith从开头匹配
istartswith不区分大小写从开头匹配
endswith不区分大小写从结尾处匹配
range范围匹配
date日期匹配
year年份
iso_year以ISO 8601标准确定的年份
month月份
day日期
week第几周
week_day周几
iso_week_day以ISO 8601标准确定的星期几
quarter季度
time时间
hour小时
minute分钟
second
regex区分大小写的正则匹配
iregex不区分大小写的正则匹配

以上字段条件查询对非JSONField 类型的模型字段,同样适用

class TestJsonField(TestCase):def setUp(self) -> None:print('====================新增数据======================')req1 = Request.objects.create(method=1,url='/mgr/student/',data={"name":"小明","age":16,"address":"广东广州","school":{"PrimarySchool":"实验小学","SecondarySchool":"第一中学"}})req2 = Request.objects.create(method=0,url='/api/teacher/',data={"name":"小王老师","courses":"英语","address":"广东深圳"})req3 = Request.objects.create(method=3,url='/api/delete/',data={"id":105,"display_idx":1})def test_json_02(self):print('====================字段条件查询======================')req4 = Request.objects.filter(url__contains='mgr')print(req4)req5 = Request.objects.filter(method__in=[0,1,2])print(req5)

输出结果

====================字段条件查询======================
<QuerySet [<Request: /mgr/student/>]>
<QuerySet [<Request: /mgr/student/>, <Request: /api/teacher/>]>
跨关系查询

Django提供了强大并且直观的方式解决跨越关联的查询,它在后台自动执行包含 JOIN 的 SQL语句。要跨越某个关联,只需使用关联的模型字段名称,并使用双下划线分隔,直至你想要的字段(可以链式跨越,无限跨度)

class TestOverRelations(TestCase):def setUp(self) -> None:# 创建用例self.config1 = Config.objects.create(name='用例1', base_url='http://127.0.0.1:8080/')self.config2 = Config.objects.create(name='用例2', base_url='http://127.0.0.1:8888/')self.case1 = Case.objects.create(config=self.config1)self.case2 = Case.objects.create(config=self.config2)def test_step_request(self):# 准备测试数据 步骤和请求step1 = Step.objects.create(belong_case=self.case1,name='步骤1')step2 = Step.objects.create(belong_case=self.case1,name='步骤2')step3 = Step.objects.create(belong_case=self.case2,name='步骤3')req1 = Request.objects.create(method=0,url='/api/teacher1/',data={"name":"小王老师","courses":"英语","address":"广东深圳"},step=step1)req2 = Request.objects.create(method=1,url='/api/teacher2/',data={"name":"小王老师","courses":"英语","address":"广东深圳"},step=step2)req3 = Request.objects.create(method=2,url='/api/teacher3/',data={"name":"小王老师","courses":"英语","address":"广东深圳"},step=step3)print(req1.step.belong_case) # 链式语法 通过请求查询步骤再查询所属的用例(通过模型关联一步步查询    print(Request.objects.filter(step=step1))   # 跨关系查询print(Request.objects.filter(step__belong_case__config__name='用例1'))   # 查询 用例1 下的步骤

跨关系查询语法:字段__关联字段

跨关系查询是根据上级数据特征查找下级的结果

用例1
<QuerySet [<Request: /api/teacher1/>]>
<QuerySet [<Request: /api/teacher1/>, <Request: /api/teacher2/>]>

修改

from django.test import TestCase# Create your tests here.from sqtp.models import Case, Config, Step, Request
from django.db.models import Valueclass TestJsonField(TestCase):def setUp(self) -> None:print('====================新增数据======================')req = Request.objects.create(method=1,url='/mgr/student/',data={"name":"小明","age":16,"address":"广东广州","school":{"PrimarySchool":"实验小学","SecondarySchool":"第一中学"}})def test_json_04(self):print('====================查询数据======================')req1 = Request.objects.all().first()print(req1)print(req1.data) # 查询data数据内容print('====================修改整个字段内容======================')req1.data={"name":"小王","age":16,"籍贯":"江西南昌"}req1.save()print(Request.objects.all().first().data) # 查看修改后的内容print('====================修改字段中json局部内容======================')req2 = Request.objects.all().first()print(req2.data['name']) # 修改前req2.data['name'] = '小红'req2.save()print(Request.objects.all().first().data['name']) # 修改后    

输出结果

====================查询数据======================
/mgr/student/
{'name': '小明', 'age': 16, 'address': '广东广州', 'school': {'PrimarySchool': '实验小学', 'SecondarySchool': '第一中学'}}
====================修改整个字段内容======================
{'name': '小王', 'age': 16, '籍贯': '江西南昌'}
====================修改字段中json局部内容======================
小王
小红

修改data字段的内容,data字段就变为了{'name': '小王', 'age': 16, '籍贯': '江西南昌'};如果只需要修改json数据中的部分内容,只需要对字典中下标名称进行赋值即可,保存后json数据的内容就修改成功了

删除

from django.test import TestCase# Create your tests here.from sqtp.models import Case, Config, Step, Request
from django.db.models import Valueclass TestJsonField(TestCase):def setUp(self) -> None:print('====================新增数据======================')req = Request.objects.create(method=1,url='/mgr/student/',data={"name":"小明","age":16,"address":"广东广州","school":{"PrimarySchool":"实验小学","SecondarySchool":"第一中学"}})def test_json_05(self):print('====================查询数据======================')req1 = Request.objects.all().first()print(req1)print(req1.data) # 查询data数据内容print('====================删除字段局部的内容======================')req1.data.pop('name')req1.save()print(Request.objects.all().first().data)print('====================删除整个字段的内容======================')req1.data = Value('null') # 设置成json的null# req1.data = None # 设置成sql的nullreq1.save()print(Request.objects.all().first().data)

输出结果

====================查询数据======================
/mgr/student/
{'name': '小明', 'age': 16, 'address': '广东广州', 'school': {'PrimarySchool': '实验小学', 'SecondarySchool': '第一中学'}}
====================删除字段局部的内容======================
{'age': 16, 'address': '广东广州', 'school': {'PrimarySchool': '实验小学', 'SecondarySchool': '第一中学'}}
====================删除整个字段的内容======================
None

删除字段json数据中的内容,则是通过pop()函数完成;删除整个字段的数据,则是字段内容置为null


http://chatgpt.dhexx.cn/article/aIbNwVro.shtml

相关文章

【java】属性别名:@JsonProperty和@JSONField的区别?【图文教程】

平凡也就两个字: 懒和惰; 成功也就两个字: 苦和勤; 优秀也就两个字: 你和我。 跟着我从0学习JAVA、spring全家桶和linux运维等知识&#xff0c;带你从懵懂少年走向人生巅峰&#xff0c;迎娶白富美&#xff01; 关注微信公众号【 IT特靠谱 】&#xff0c;每一篇文章都是心得总结…

fastjson @JSONField format 不生效的原因

&#xff08;以下问题已在fastjson高版本优化<目前我用的是1.2.83版本>&#xff09; 在一次接手项目中发现&#xff0c;http接口返回json数据&#xff0c;Date类型的变量用JSONField format注解格式化不起作用。排查原因&#xff1a; 1&#xff09;查http接口序列化是不…

formdata和json

HTTP content-type Content-Type&#xff08;内容类型&#xff09;&#xff0c;一般是指网页中存在的 Content-Type&#xff0c;用于定义网络文件的类型和网页的编码&#xff0c;决定浏览器将以什么形式、什么编码读取这个文件&#xff0c;这就是经常看到一些 PHP 网页点击的结…

常用注解@JsonField、@JsonFormat、@DateTimeFormat区别

JsonFormat 该注解来源于jackson包中的注解&#xff0c;主要用来控制后端返回给前端的日期格式&#xff0c;通常用在返回给前端的实体类中。 案例如下&#xff1a; class User{private Integer id;JsonFormat(pattern”yyyy-MM-dd”,timezone”GMT8”)private Date birthday;…

Springboot中使用@JsonProperty和@JSONField

2个注解都是为了解决json字符串的某些属性名和JavaBean中的属性名匹配不上的问题。 例子&#xff0c;不使用注解的情况 Data public class Routine {private Integer TTS_voice;} PostMapping("/test8")public Routine test8(RequestBody Routine routine){retur…

@JSONField

1.引入依赖 <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency> 2.JSONField注解可以用在方法&#xff08;method&#xff09;&#xff0c;属性&#xff0…

@JsonField 不起作用

在Springboot中默认的JSON解析框架是jackson&#xff0c;引入alibaba的fastjson&#xff0c;使用JSONField 去接收带有native的json请求&#xff0c;实体类名需要做一个转换&#xff0c;但是接受json串的时候&#xff0c;用到JsonField不起作用&#xff0c;接受过来还是null。 …

一眼看清@JSONField注解使用与效果

JSONField是做什么用的 JSONField是fastjson的一个注解&#xff0c;在fastjson解析一个类为Json对象时&#xff0c;作用到类的每一个属性&#xff08;field&#xff09;上。 通过用JSONField注解一个类的属性&#xff0c;我们可以达到以下目标 指定field对应的key名称&#…

perclos

WierwiIIe驾驶模拟器上的实验结果证明&#xff0c;眼睛的闭合时间一定程度地反映疲劳&#xff0c; 如图 所示。 在此基础上&#xff0c; 卡内基梅隆研究所经过反复实验和论证&#xff0c;提出了度量疲劳/瞌睡的物理量 PERCLOS &#xff08;Percentage of EyeIid CIosure over t…

机器视觉毕业设计 深度学习驾驶人脸疲劳检测系统 - python opencv

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的…

Android studio开发 课设必备疲劳检测app

使用android内置摄像头&#xff0c;可以根据人的状态判定是否疲劳&#xff0c;界面设计较好&#xff0c;检测后还可以回到主界面 运行截图如下&#xff0c;获取源码有偿&#xff0c;拒绝白嫖党~

基于MATLAB的人眼开度疲劳检测识别

一、课题背景 目前&#xff0c;随着人们生活水平的提高&#xff0c;各国人民汽车保有量也越来越多&#xff0c;伴随而来的是交通事故也在不断增多。研究表明&#xff0c;疲劳驾驶是造成交通事故日益严重的重要原因。开展驾驶员疲劳检测和预警的研究工作&#xff0c;有着十分重…

Dlib+Opencv库实现疲劳检测

文章目录 1.关键点检测2.算法实现的核心点3.算法实现&#xff08;1&#xff09;人脸的关键点集合&#xff08;2&#xff09;加载人脸检测库和人脸关键点检测库&#xff08;3&#xff09;绘制人脸检测的框&#xff08;4&#xff09;对检测之后的人脸关键点坐标进行转换&#xff…

Python基于OpenCV的工作疲劳检测系统[源码&UI界面&部署教程]

1.图片演示 2.视频演示 [项目分享]Python基于OpenCV的实时疲劳检测[源码&#xff06;演示视频&#xff06;部署教程]_哔哩哔哩_bilibili 3.检测方法 1&#xff09;方法 与用于计算眨眼的传统图像处理方法不同&#xff0c;该方法通常涉及以下几种组合&#xff1a; 1、眼睛定…

Opencv之疲劳检测

项目要求 在一段视频中&#xff0c;通过检测人眨眼的次数来判断他的疲劳程度。 代码实现 1、导入工具包 from scipy.spatial import distance as dist import numpy as np import dlib import cv22、对脸上的部位进行定义 在关键点定位的官方文档中&#xff0c;提取68个关…

人脸识别-驾驶疲劳检测(1) 眨眼检测

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、背景 &#xff08;1&#xff09;环境搭建 &#xff08;2&#xff09;下载开源数据集 &#xff08;3&#xff09;视觉疲劳检测原理 二、代码示例 三、效…

人脸检测高级:疲劳检测

今天我们实现疲劳检测。 如果眼睛已经闭上了一段时间&#xff0c;我们会认为他们开始打瞌睡并发出警报来唤醒他们并引起他们的注意。我们测试一段视频来展示效果。同时代码中保留开启摄像头的的代码&#xff0c;取消注释即可使用。 使用 OpenCV 构建犯困检测器 要开始我们的实…

数字图像处理课程设计-疲劳检测系统

文章目录 数字图像处理课程设计-疲劳检测系统前言一、课程设计任务二、设计框图三、准备工作四、任务流程&#xff14;.&#xff11;视频预处理4.2图片分割 五、结果六、项目总结 数字图像处理课程设计-疲劳检测系统 前言 此系统基于MATLAB设计,核心思想是PERCLOS算法. 参考文…

MATLAB的疲劳检测系统

一、课题介绍 本设计针对现有逐帧眼睛定位方法计算量大&#xff0c;速度慢的缺点&#xff0c;提出一种用于疲劳驾驶实时监测的眼睛定位方法&#xff0c;该方法能够在保证眼睛定位准确性的同时&#xff0c;减少人脸定位的计算量&#xff0c;从而提高图像处理速度&#xff0c;实现…

毕业设计 机器视觉 opencv 深度学习 驾驶人脸疲劳检测系统 -python

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业…