九、REST framework接口开发:基于APIView接口实现
1、新建数据表<项目开发很少使用ForeignKey>,本项目也不使用,只使用M2M
# 接口请求参数表 class Interface_request_data(models.Model): db_table = 'interface_request_data' id = models.AutoField(max_length=200, verbose_name='主键', primary_key=True, unique=True) interface_name = models.CharField(max_length=50, verbose_name='接口名称') request_url = models.CharField(max_length=200, verbose_name='接口请求地址', unique=True) request_path = models.CharField(max_length=200, verbose_name='接口请求路径') is_run = models.CharField(max_length=20, verbose_name='接口是否运行') request_method = models.CharField(max_length=20, verbose_name='接口请求类型') request_headers = models.JSONField(default=dict, blank=True, verbose_name='json格式的接口请求头') create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") case_data = models.ManyToManyField(verbose_name="标签", to="Interface_case_data") def __str__(self): return self.interface_name # 接口请求用例表 class Interface_case_data(models.Model): db_table = 'interface_case_data' id = models.AutoField(max_length=200, verbose_name='主键', primary_key=True, unique=True) parent_id = models.IntegerField(max_length=200, verbose_name='父类id', unique=True) interface_case_name = models.CharField(max_length=50, verbose_name='接口用例名称') request_data = models.CharField(max_length=200, verbose_name='接口请求参数') request_expected_results = models.CharField(max_length=200, verbose_name='接口预期结果', unique=True) create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") def __str__(self): return self.interface_case_name
2、接口开发,增删改查查,查查为单条数据查询和全部查询
# 创建序Interface_case_data列化器类 class CaseDataSerializer(serializers.ModelSerializer): class Meta: model = Interface_case_data fields = ["id", "interface_case_name"] # 创建Interface_request_data序列化器类 class InterfaceDataSerializer(serializers.ModelSerializer): # required=False非必填字段,如post请求时,可以携带此字段也可以不携带 # read_only=True表示只读字段,当为True时,字段数据只读不会写入数据库 # case_data为get请求时,返回字段数据,必须携带,当为post请求时,也可以使用,为区分两者关系,添加case_id用于维护M2M # case_data 基于ManyToManyField使用嵌套的形式,嵌套使用连接: # https://www.cnblogs.com/guanyf/p/18585619 case_data = CaseDataSerializer(many=True, required=False, read_only=True) # 表示只接受 List形式的数据,结合钩子使用,required=False表示非必填项 case_id = serializers.ListField(required=False) class Meta: model = Interface_request_data fields = ["interface_name", "request_url", "request_path", "case_data", "case_id"] # 字段钩子,转换为QuerySet对象 def validate_case_id(self, value): # QuerySet 对象,当传递QuerySet对象时,序列化器字段帮助我们维护多对多的关系表 case_date_db = Interface_case_data.objects.filter(id__in=value) return case_date_db class RequestDataView(MyAPIView): # 认证类,没有时为空 authentication_classes = [] permission_classes = [] # 新建get方法 def get(self, request, *args, **kwargs): # 查询数据库数据 queryset = Interface_request_data.objects.all() # 进行序列化 ser = InterfaceDataSerializer(instance=queryset, many=True) # 返回序列化后的数据 return Response(ser.data) # 新建post方法 def post(self, request, *args, **kwargs): ser = InterfaceDataSerializer(data=request.data) # ser.is_valid(),校验字段方法,根据序列化器 if ser.is_valid(): try: # 注意,此处的case_id表示移除序列化数据集合中的数据,当case_id没有时,报错KeyError: 'case_id' # 报错时,抛出异常,不做任何处理。 # 使用case_id目的:1、演示可以自定义字段并且可以通过钩子重新定义字段 # 2、因为DRF的默认序列化器并不直接支持通过嵌套序列化器来更新多对多关系,通过钩子可以维护 case_queryset = ser.validated_data.pop('case_id') ser.validated_data['case_data'] = case_queryset except KeyError as e: pass ser.save() # ser.data为默认写法,数据从ser.data中获取,详细逻辑查看源码 return Response(ser.data) else: # 当序列化错误时,错误信息字段写入ser.errors,如:字段过长等信息 return Response(ser.errors) class RequestDataDetailView(MyAPIView): # 认证类,没有时,注释掉 authentication_classes = [] # 单查询 def get(self, request, *args, **kwargs): # 获取所有数据 db_data = Interface_request_data.objects.filter(pk=kwargs["id"]).all() ser = InterfaceDataSerializer(instance=db_data, many=True) # 序列化 return Response(ser.data) # 返回 # 单条数据更新,演示m2m数据更新,当没有m2m时,手动处理逻辑 def put(self, request, *args, **kwargs): # 获取单条数据 db_date = Interface_request_data.objects.filter(id=kwargs["id"]).first() # 进行序列化 ser = InterfaceDataSerializer(instance=db_date, data=request.data) if ser.is_valid(): # 验证字段,注意:验证字段根据data进行验证 try: # 判断是否包含case_id字段,如果有就替换成case_data # ser.validated_data.pop('case_id')只配合is_valid使用 # 通过字段钩子case_id的值,已经替换为queryset对象 case_queryset = ser.validated_data.pop('case_id') # 因models中,只接受字段case_data,不接收case_id,需要替换key,方便m2m进行关联 ser.validated_data['case_data'] = case_queryset except KeyError as e: pass # 触发save方法时,自动进行m2m字段抽取和组合,具体逻辑,请查看源码 ser.save() return Response(ser.data) else: return Response(ser.errors) def delete(self, request, *args, **kwargs): db_data = Interface_request_data.objects.filter(id=kwargs["id"]).first() # 当有关联时,自动删除联系 db_data.delete() return Response()
3、url配置
urlpatterns = [ # <str:version> 表示捕获url该部分的信息,并赋值给version,并且这个变量在视图函数中可以通过version这个名称来访问 # 当然在请求中可以获取到version这值,但是会导致后续很多复杂逻辑,不建议怎么做 # URLPathVersioning会对version进行处理,可以避免其他逻辑性问题 path('api/<str:version>/user/', views.RequestDataView.as_view()), re_path("api/(?P<version>.+)/user/(?P<id>\d+)", views.RequestDataDetailView.as_view()), ]
4、通过源码可以知道,当save操作时,是调用了父类的update和create方法,那么我们可以重写update和create,降低代码的耦合性
class CaseDataSerializer(serializers.ModelSerializer): class Meta: model = Interface_case_data fields = ["id", "interface_case_name"] # 创建Interface_request_data序列化器类 class InterfaceDataSerializer(serializers.ModelSerializer): # required=False非必填字段,如post请求时,可以携带此字段也可以不携带 # read_only=True表示只读字段,当为True时,字段数据只读不会写入数据库 # case_data为get请求时,返回字段数据,必须携带,当为post请求时,也可以使用,为区分两者关系,添加case_id用于维护M2M # case_data 基于ManyToManyField使用嵌套的形式,嵌套使用连接: # https://www.cnblogs.com/guanyf/p/18585619 case_data = CaseDataSerializer(many=True, required=False, read_only=True) # 表示只接受 List形式的数据,结合钩子使用,required=False表示非必填项 case_id = serializers.ListField(required=False) class Meta: model = Interface_request_data fields = ["interface_name", "request_url", "request_path", "case_data", "case_id"] # 字段钩子,转换为QuerySet对象 def validate_case_id(self, value): # QuerySet 对象,当传递QuerySet对象时,序列化器字段帮助我们维护多对多的关系表 case_date_db = Interface_case_data.objects.filter(id__in=value) return case_date_db # 重写父类的create方法 def create(self, validated_data): example_relationship_data = None if 'case_id' in validated_data: # 从验证后的数据中剔除多对多字段,并拿到相关数据 example_relationship_data = validated_data.pop('case_id') # 先提交没有m2m的数据 instance = Interface_request_data.objects.create(**validated_data) # 检查是否有多对多字段数据需要更新 if example_relationship_data is not None: # 如果有m2m数据,使用set方法进行更新m2m数据 # case_data是 m2m 字段,在models中有规定,然后使用了 set() 方法来更新多对多关系 instance.case_data.set(example_relationship_data) return instance # 重写父类的update方法 def update(self, instance, validated_data): example_relationship_data = None # 从验证后的数据中剔除多对多字段,并拿到相关数据 if 'case_id' in validated_data: # 从验证后的数据中剔除多对多字段,并拿到相关数据 example_relationship_data = validated_data.pop('case_id') # 保存不包含多对多字段的模型实例 instance.save() # 检查是否有多对多字段数据需要更新 if example_relationship_data is not None: # case_data是 m2m 字段,在models中有规定,然后使用了 set() 方法来更新多对多关系 instance.case_data.set(example_relationship_data) return instance class RequestDataView(MyAPIView): # 认证类,没有时为空 authentication_classes = [] permission_classes = [] # 新建get方法 def get(self, request, *args, **kwargs): # 查询数据库数据 queryset = Interface_request_data.objects.all() # 进行序列化 ser = InterfaceDataSerializer(instance=queryset, many=True) # 返回序列化后的数据 return Response(ser.data) # 新建post方法 def post(self, request, *args, **kwargs): ser = InterfaceDataSerializer(data=request.data) # ser.is_valid(),校验字段方法,根据序列化器 if ser.is_valid(): ser.save() # ser.data为默认写法,数据从ser.data中获取,详细逻辑查看源码 return Response(ser.data) else: # 当序列化错误时,错误信息字段写入ser.errors,如:字段过长等信息 return Response(ser.errors) class RequestDataDetailView(MyAPIView): # 认证类,没有时,注释掉 authentication_classes = [] permission_classes = [] # 单查询 def get(self, request, *args, **kwargs): # 获取所有数据 db_data = Interface_request_data.objects.filter(pk=kwargs["id"]).all() ser = InterfaceDataSerializer(instance=db_data, many=True) # 序列化 return Response(ser.data) # 返回 # 单条数据更新,演示m2m数据更新,当没有m2m时,手动处理逻辑 def put(self, request, *args, **kwargs): # 获取单条数据 db_date = Interface_request_data.objects.filter(id=kwargs["id"]).first() # 进行序列化 ser = InterfaceDataSerializer(instance=db_date, data=request.data) if ser.is_valid(): # 验证字段,注意:验证字段根据data进行验证 # 根据save方法,当instance不为空时,调用update方法 ser.save() return Response(ser.data) else: return Response(ser.errors) def delete(self, request, *args, **kwargs): db_data = Interface_request_data.objects.filter(id=kwargs["id"]).first() # 当有关联时,自动删除联系 db_data.delete() return Response()

浙公网安备 33010602011771号