一、 数据库查询强化训练 1. 字段条件查询 字段查询是指如何指定SQL WHERE子句的内容。
它们用作QuerySet的filter()
, exclude()
和get()
方法的关键字参数。
其基本格式是:field__lookuptype=value
,注意其中是 双下划线
。
默认查找类型为exact(精确匹配)。
lookuptype的类型有:
Django的数据库API支持20多种查询类型,下表列出了所有的字段查询参数:
字段名 说明 exact 精准匹配 iexact 不区分大小写的精准匹配 contains 包含匹配 icontains 不区分大小写的包含匹配 in 在 。。。之内的匹配 gt 大于 gte 大于等于 lt 小于 lte 小于等于 startswith 从开头匹配 istartswith 不区分大小写的从开头匹配 endswith 从结尾处匹配 iendswith 不区分大小写的从结尾处匹配 range 范围匹配 date 日期匹配 year 年份匹配 iso_year 以 ISO 8601 标准确定的年份 month 月份 day 日期 week 第几周 ios_week_day 以 ISO 8601 标准确定的星期几 quarter 季度 time 时间 hour 小时 minute 分钟 second 秒 regex 区分大小写的正则匹配 iregex 不区分大小写的正则匹配
1 2 3 4 5 6 7 8 9 10 class TestFieldQuery (TestCase ): def setUp (self ) -> None : Request.objects.create(url='/api/request/demo1' ,data={'name' :'小明' ,'age' :18 ,'addr' :'nanjing' ,'father' :{'name' :'xiaogang' ,'age' :40 }}) def test_contains_query (self ): req = Request.objects.filter (url__contains='demo' ) print (req) def test_in_query (self ): req = Request.objects.filter (url__in=['/api/request/demo1' ,'/api/request/demo2' ]) print (req)
执行测试
1 python manage.py test sqtp.tests.TestFieldQuery
2. 夸关系查询 Django提供了强大并且直观的方式解决跨越关联的查询,它在后台自动执行包含JOIN的SQL语句。
要跨越某个关联,只需使用关联的模型字段名称,并使用双下划线分隔,直至你想要的字段(可以链式跨 越,无限跨度).
例如
1 2 res1=Case.objects.filter (tags__name='smoketest' )
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class TestOverRelations (TestCase ): def setUp (self ) -> None : self.suite_conf = Config.objects.create(name='套件1' ) self.suite = Suite.objects.create(config=self.suite_conf) self.config = Config.objects.create(name='用例1' ) self.case = Case.objects.create(config=self.config,suite=self.suite) def test_case_step (self ): Step.objects.create(belong_case=self.case ,name='步骤1' ) Step.objects.create(belong_case=self.case ,name='步骤2' ) Step.objects.create(belong_case=self.case ,name='步骤3' ) steps=Step.objects.filter (belong_case__suite__config__name='套件1' ) print (steps)
二、 接口开发实战 - REST 框架入门 Django REST framework (以下简称 DRF或REST框架)是一个开源的 Django 扩展,提供了便捷的REST API 开发框架,拥有以下特性:
直观的 API web 界面。 多种身份认证和权限认证方式的支持。 内置了 OAuth1 和 OAuth2 的支持。 内置了限流系统。 根据 Django ORM 或者其它库自动序列化。 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要。 可扩展性,插件丰富。 广泛使用,文档丰富 1. 安装 REST (djangorestframework)框架 1 pip install djangorestframework
2. 配置 REST (djangorestframework)框架 在 settings.py 中 注册 REST 框架
1 2 3 4 5 INSTALLED_APPS = [ 'rest_framework' ]
3. REST 运行原理
相比于原生django开发的web应用,多了一层序列化器(Serializer)
序列化器和表单都是基于Field进行字段验证,而Field都来自于rest_framework.fields模块,相当于把django的封装了一层。
三、 REST 框架基本组件 —- Serializer Serializer 的作用:实现序列化和 反序列化
序列化 : 就是将 python 数据对象 转化 成方便传输的文本格式, 如 json、xml等 反序列化 : 就是将 文本格式的 数据 转化为 python 数据对象 序列化 通常定义在 应用程序下单独文件中 serializer.py
1. 模型改造,添加元类 模型的元数据 : 是指除了字段为的所有内容,比如 排序方式,数据库名等等
增加元数据的方法 : 在模型类中添加 子类, 名字固定为 Meta
, 然后在这个 子类 下 增加各种元数据选项。
1 2 3 4 5 6 from django.db import modelsclass Request (models.Model): ... class Meta : ordering = ['id' ] db_table = ['reqquest' ]
2. 创建 序列化类 开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json 之类的表示形式的方式 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 from rest_framework import serializersfrom sqtp.models import Step, Requestclass RequestSerializer (serializers.Serializer): method_choices = ( (0 , 'GET' ), (1 , 'POST' ), (2 , 'PUT' ), (3 , 'DELETE' ), ) step = serializers.RelatedField(queryset=Step.objects.all (),allow_null=True ) method = serializers.ChoiceField(choices=method_choices, default=0 ) url = serializers.CharField() params = serializers.JSONField(allow_null=True ) headers = serializers.JSONField(allow_null=True ) cookies = serializers.JSONField(allow_null=True ) data = serializers.JSONField(allow_null=True ) json = serializers.JSONField(allow_null=True ) def create (self, validated_data ): """ 根据提供的验证过的数据创建并返回一个新的`Snippet`实例。 """ return Request.objects.create(**validated_data) def update (self, instance, validated_data ): """ 根据提供的验证过的数据创建并返回一个新的`Snippet`实例。 """ instance.step =validated_data.get('step' ,instance.step) instance.method =validated_data.get('method' ,instance.method) instance.url =validated_data.get('url' ,instance.url) instance.params =validated_data.get('params' ,instance.params) instance.headers =validated_data.get('headers' ,instance.headers) instance.cookies =validated_data.get('cookies' ,instance.cookies) instance.data =validated_data.get('data' ,instance.data) instance.json =validated_data.get('json' ,instance.json)
序列化器类的第一部分定义了序列化/反序列化的字段。
create() 和 update() 方法定义了在调用serializer.save() 时如何创建和修改完整的实例
3. 使用序列化类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from django.test import TestCasefrom sqtp.models import Step, Requestfrom sqtp.serializers import RequestSerializerfrom rest_framework.renderers import JSONRendererfrom rest_framework.parsers import JSONParserclass TestRequestSerializer (TestCase ): req1=Request.objects.create(url='/demo1' ,data={'name' :'小明' ,'age' :18 ,'addr' :'nanjing' }) req2=Request.objects.create(url='/demo1' ,params={'name' :'小明' ,'age' :18 ,'addr' :'nanjing' }) req1_serializer = RequestSerializer(req1) print (req1_serializer.data) content = JSONRenderer().render(req1_serializer.data) print (content)
执行测试
1 python manage.py test sqtp.test_serializers
返回
1 2 {'step': None, 'method': 0, 'url': '/demo1', 'params': None, 'headers': None,'cookies': None, 'data': {'name': '小明', 'age': 18, 'addr': 'nanjing'}, 'json': None}b'{"step":null,"method":0,"url":"/demo1","params":null,"headers":null,"cookies":null,"data":{"name":"\xe5\xb0\x8f\xe6\x98\x8e","age":18,"addr":"nanjing"},"json":null}'
反序列化是类似的。测试类再新增以下代码,实现反序列化
1 2 3 4 5 6 7 8 9 10 11 import iostream = io.BytesIO(content) data = JSONParser().parse(stream) serializer = RequestSerializer(data=data) print (serializer.is_valid()) print (serializer.validated_data) serializer.save()
执行测试
1 python manage.py test sqtp.test_serializers
返回
1 2 3 4 ... True OrderedDict([('step', None), ('method', 0), ('url', '/demo1'), ('params', None), ('headers', None), ('cookies', None), ('data', {'name': '小明', 'age': 18, 'addr': 'nanjing'}), ('json', None)])
除了序列化模型实例,序列化器还可以序列化查询结果集(querysets),只需要为serializer添加一个many=True
标志。
1 2 3 serializers= RequestSerializer(Request.objects.all (),many=True ) print (serializers.data)
4. 改进 序列化器(重点) 用 ModelSerializer
代替 Serializer
类作为自定义序列化器的父类,减少重复代码的编写
使用 ModelSerializer
重构序列化类 1 2 3 4 5 6 7 8 9 10 from rest_framework import serializersfrom sqpt.models import Request, Step, Config, Caseclass RequestSerializer (serializers.ModelSerializer): class Meta : model = Request fields = ['step' , 'method' , 'url' , 'params' , 'headers' , 'data' , 'json' ]
打印序列化器类实例的结构(representation)查看它的所有字段
1 2 3 4 print (repr (serializer))
返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 RequestSerializer(data={'id': 13, 'step': None, 'method': 0, 'url': '/demo1', 'params': None, 'headers': None, 'data': {'name': '小明', 'age': 18, 'addr': 'nanjing'}, 'json': None}): id = IntegerField(label='ID', read_only=True) step = PrimaryKeyRelatedField(allow_null=True, queryset=Step.objects.all(), required=False, validators=[<Un iqueValidator(queryset=Request.objects.all())>]) method = ChoiceField(choices=((0, 'GET'), (1, 'POST'), (2, 'PUT'), (3, 'DELETE')), label='请求方法', requir ed=False, validators=[<django.core.validators.MinValueValidator object>, <django.core.validators.MaxValueValida tor object>]) url = CharField(label='请求路径', max_length=1000, required=False) params = JSONField(allow_null=True, decoder=None, encoder=None, label='Url参 数', required=False, style={'ba se_template': 'textarea.html'}) headers = JSONField(allow_null=True, decoder=None, encoder=None, label='请求 头', required=False, style={'ba se_template': 'textarea.html'}) data = JSONField(allow_null=True, decoder=None, encoder=None, label='Data参 数', required=False, style={'bas e_template': 'textarea.html'}) json = JSONField(allow_null=True, decoder=None, encoder=None, label='Json参 数', required=False, style={'bas e_template': 'textarea.html'})
ModelSerializer
类并不会做任何特别神奇的事情,它们只是创建序列化器类的快捷方式:
一组自动确定的字段。 默认简单实现的 create() 和 update() 方法 5. 视图编写 编辑 sqtp/views.py
,导入以下库
1 2 3 4 5 from django.http import HttpResponse, JsonResponsefrom django.views.decorators.csrf import csrf_exemptfrom rest_framework.parsers import JSONParserfrom sqtp.models import Requestfrom sqtp.serializers import RequestSerializer
编写一个视图可以返回所有的请求数据
1 2 3 4 5 def request_list (request ): if request.method == 'GET' : serializer= RequestSerializer(Request.objects.all (),many=True ) return JsonResponse(serializer.data, safe=False )
创建 sqtp/urls.py
, 写入路由
1 2 3 4 5 6 from django.urls import pathfrom sqtp import viewsurlpatterns = [ path('requests/' ,views.request_list) ]
总路由引入子路由 autotpsite/urls.py
1 2 3 4 5 from django.urls import path,includeurlpatterns = [ path('' ,include('sqtp.urls' )) ]
启动server服务并测试
1 python manage.py runserver
6. 接口开发-DRF-进阶 接口开发本质上是处理请求和响应,包括了处理请求参数,判断请求方法,处理响应字段,响应码等
第一个工具,函数视图 装饰器 @api_view
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from django.http import HttpResponse, JsonResponsefrom rest_framework.decorators import api_viewfrom sqtp.models import Requestfrom rest_framework.response import Responsefrom sqtp.serializers import RequestSerializer@api_view(['GET' ,'POST' ] ) def request_list (request, format =None ): if request.method == 'GET' : serializer = RequestSerializer(Request.objects.all (), many=True ) return Response(serializer.data)
装饰器的作用是 确保你在视图中接收到 Request 实例,并将上下文添加到 Response ,以便可以执行内容协商 .
包装器还提供了诸如在适当时候返回 405 Method Not Allowed 响应,并处理在使用格式错误的输入来访问 request.data 时发生的任何 ParseError 异常
1 2 3 4 5 6 7 8 @api_view(['GET' ] ) def request_detail (request, _id , format =None ): try : req_obj = Request.objects.get(id =_id ) except Exception: return Response(status=status.HTTP_404_NOT_FOUND) serializer = RequestSerializer(req_obj) return Response(serializer.data)
6. 请求与响应 在纯django中,request和response只能实现有限的功能。REST框架对其作了扩展 :
请求对象(Request objects) REST框架引入了一个扩展了常规 HttpRequest 的 Request 对象,并提供了更灵活的请求解析。
Request 对象的核心功能是 request.data 属性,它与 request.POST 类似,但对于使用Web API更为有用。
1 2 request.POST request.data
响应对象(Response objects) REST框架还引入了一个 Response 对象,这是一种获取未渲染(unrendered)内容的TemplateResponse 类型,并使用内容协商来确定返回给客户端的正确内容类型。
默认情况下,Response把响应内容嵌套在默认的模板中返回出去,所以我们看到的内容是网页形式,而不是单纯的数据。
响应数据格式 - 扩展 为API路径添加对格式后缀 如http://example.com/api/items/4.json之类的URL
视图中添加一个 format 关键字参数。
1 2 3 4 5 6 @api_view(['GET' ] ) def request_list (request,format =None ): if request.method == 'GET' : serializer = RequestSerializer(Request.objects.all (), many=True ) return Response(serializer.data)
修改路由文件 sqtp/urls.py
1 2 3 4 5 6 7 8 from django.urls import pathfrom sqtp import viewsfrom rest_framework.urlpatterns import format_suffix_patternsurlpatterns = [ path('requests/' ,views.request_list) ] urlpatterns = format_suffix_patterns(urlpatterns)
访问http://127.0.0.1:8000/requests.json ,返回了json格式的数据
查询单个数据 - 扩展 1 2 3 4 5 6 7 8 9 10 11 12 13 @api_view(['GET' ] ) def request_detail (request,_id ,format =None ): """ 获取,更新或删除一个req实例。 """ try : req_obj = Request.objects.get(pk=_id ) except Request.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) 码 if request.method == 'GET' : serializer = RequestSerializer(req_obj) return Response(serializer.data)
更新路由:sqtp/urls.py
1 2 3 4 5 urlpatterns = [ path('requests/' , views.request_list), path('requests/<int:_id>' , views.request_detail) ] urlpatterns = format_suffix_patterns(urlpatterns)
访问http://127.0.0.1:8000/requests/2
或 http://127.0.0.1:8000/requests/2.json
附录 可用的Meta选项:模型 Meta 选项 | Django 文档 | Django (djangoproject.com)