drf-day2 1. 知识回顾 1 2 3 4 5 6 7 8 9 10 1. 前后端分离的架构 后端负责数据的提供 前端完成页面的展示以及数据的渲染 二者通过ajax进行交互 2. 接口API 3. RESTFul架构 遵从了REST规范 4. Django类视图 FBV: function base view 函数视图 CBV: class base view 类视图 5. DRF的视图开发 APIView继承了Django的View类
2. Request模块
主要功能: 用来获取请求中所包含的各种参数
入口: request = self.initialize_request(request, *args, **kwargs)
Request类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Request : def __init__ (self, request, parsers=None , authenticators=None , negotiator=None , parser_context=None ): assert isinstance (request, HttpRequest), ( .format (request.__class__.__module__, request.__class__.__name__) ) self._request = request self.parsers = parsers or () self.authenticators = authenticators or () self.negotiator = negotiator or self._default_negotiator() self.parser_context = parser_context self._data = Empty self._files = Empty self._full_data = Empty self._content_type = Empty self._stream = Empty
DRF获取参数的方式
GET请求可以通过request.GET
以及request.query_params
来获取参数
POST请求有多种传递参数的形式,request.data
可以获取多种类型的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class StudentAPIView (APIView ): def get (self, request, *args, **kwargs ): print ("get Success" ) print (request._request.GET.get("email" )) print (request.GET.get("email" )) print (request.query_params.get("pwd" )) return Response("GET OK" ) def post (self, request, *args, **kwargs ): print ("post Success" ) print (request._request.POST.get("email" )) print (request.POST.get("email" )) print (request.data) return Response("POST OK" )
3. 渲染模块 render
渲染器: 决定了你的数据以何种形式返回到前端
源码流程
源码入口: self.finalize_response(request, response, *args, **kwargs)
找到neg = self.perform_content_negotiation(request, force=True)
来返回渲染器
获取当前视图所配置的渲染器: renderers = self.get_renderers()
通过return [renderer() for renderer in self.renderer_classes]
找到配置的渲染器
在DRF的setting模块中定义默认的渲染器DEFAULT_RENDERER_CLASSES
使用方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES' : [ 'rest_framework.renderers.JSONRenderer' , 'rest_framework.renderers.BrowsableAPIRenderer' , ], } class StudentAPIView (APIView ): renderer_classes = (BrowsableAPIRenderer,) def get (self, request, *args, **kwargs ): print ("get Success" )
4. DRF解析模块 parser
解析模块: 指定当前视图可以接受什么类型的参数 form-data www-url-encode json
源码解析
源码入口: self.initialize_request(request, *args, **kwargs)
获取解析器: parsers=self.get_parsers(),
获取配置的解析器: return [parser() for parser in self.parser_classes]
使用方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 REST_FRAMEWORK = { ...... 'DEFAULT_PARSER_CLASSES' : [ 'rest_framework.parsers.JSONParser' , 'rest_framework.parsers.FormParser' , 'rest_framework.parsers.MultiPartParser' ], } class StudentAPIView (APIView ): parser_classes = [JSONParser] def get (self, request, *args, **kwargs ): print ("get Success" )
5. DRF的异常处理
异常模块主要是处理在各个方法执行过程中所发生的问题
异常源码
异常处理源码入口: response = self.handle_exception(exc)
获取处理异常的方法: exception_handler = self.get_exception_handler()
返回处理异常的方法: return self.settings.EXCEPTION_HANDLER
异常处理的逻辑在: rest_framework.views.exception_handler
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 def handle_exception (self, exc ): """ Handle any exception that occurs, by returning an appropriate response, or re-raising the error. """ if isinstance (exc, (exceptions.NotAuthenticated, exceptions.AuthenticationFailed)): auth_header = self.get_authenticate_header(self.request) if auth_header: exc.auth_header = auth_header else : exc.status_code = status.HTTP_403_FORBIDDEN exception_handler = self.get_exception_handler() context = self.get_exception_handler_context() response = exception_handler(exc, context) if response is None : self.raise_uncaught_exception(exc) response.exception = True return response
自定义异常的处理
对于DRF无法处理的某些异常,我们可以通过自定义的方式完成处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from rest_framework.response import Responsefrom rest_framework.views import exception_handler as drf_exception_handlerdef exception_handler (exc, context ): error = "%s %s %s" % (context["view" ], context["request" ].method, exc) print (error) response = drf_exception_handler(exc, context) if response is None : return Response({"error_message" : "上帝请稍等,程序猿正在加紧处理中~" }) return response
1 2 3 4 5 # 总结 1. 异常处理是通过`self.get_exception_handler()` 获取异常处理的方法2. 通过`return self.settings.EXCEPTION_HANDLER` 获取DRF默认的处理异常的方法3. 自定义异常时可以先让drf处理已知的异常,DRF无法处理的异常由我们自定义处理4. 可以通过`exception_handler` 来判断异常是否已经被处理
6. Response模块 Response类 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 class Response (SimpleTemplateResponse ): def __init__ (self, data=None , status=None , template_name=None , headers=None , exception=False , content_type=None ): super ().__init__(None , status=status) if isinstance (data, Serializer): msg = ( 'You passed a Serializer instance as data, but ' 'probably meant to pass serialized `.data` or ' '`.error`. representation.' ) raise AssertionError(msg) self.data = data self.template_name = template_name self.exception = exception self.content_type = content_type """ data=None, 响应回去的数据 status=None, 响应的状态码 template_name=None 渲染的模板地址 不处理 headers=None, 响应头 exception=False, 是否有异常 content_type=None 数据格式 """
7. DRF 序列化组件[重点]
DRF常用的序列化器类: Serializer
(偏底层)、ModelSerializer
(常用)、ListSerializer
(做群体操作)
模型设计 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 MEDIA_ROOT = os.path.join(BASE_DIR, "media/" ) from django.views.static import servefrom django.conf import settingsre_path(r'^media/(?P<path>.*)' , serve, {"document_root" : settings.MEDIA_ROOT}), class Employee (models.Model): gender_choices = ( (0 , "male" ), (1 , "female" ), (2 , "other" ), ) username = models.CharField(max_length=100 ) password = models.CharField(max_length=64 ) gender = models.SmallIntegerField(choices=gender_choices, default=0 ) phone = models.CharField(max_length=11 , null=True , blank=True ) pic = models.ImageField(upload_to="pic/" , default="pic/1.jpg" ) class Meta : db_table = "bz_employee" verbose_name = "员工" verbose_name_plural = verbose_name def __str__ (self ): return self.username
Serializer初始
1 2 3 4 5 6 7 8 class EmployeeSerializer (serializers.Serializer): """ 定义序列化器类: 需要为每一个model编写对应的序列化器类 """ username = serializers.CharField() password = serializers.CharField() gender = serializers.IntegerField() pic = serializers.ImageField()
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 class EmployeeAPIView (APIView ): def get (self, request, *args, **kwargs ): emp_id = kwargs.get("id" ) if emp_id: emp_obj = Employee.objects.get(pk=emp_id) employee_serializer = EmployeeSerializer(emp_obj).data return Response({ "status" : 200 , "message" : "查询单个员工成功" , "results" : employee_serializer }) else : employee_objects_all = Employee.objects.all () emp_data = EmployeeSerializer(employee_objects_all, many=True ).data print (emp_data) return Response({ "status" : 200 , "message" : "查询所有员工成功" , "results" : emp_data })
1 2 3 4 5 # 总结 1. 需要为每个模型指定一个单独的序列化器类2. 在为前端返回数据时,需要响应序列化后的 .data的值3. 在序列化器中的字段必须与模型的字段保持一致,否则无法序列化, 如果某个字段不想序列化时,可以不写4. 序列化多个对象时,需要指定many=True
对字段进行自定义 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 class EmployeeSerializer (serializers.Serializer): """ 定义序列化器类: 需要为每一个model编写对应的序列化器类 """ username = serializers.CharField() password = serializers.CharField() aaa = serializers.SerializerMethodField() def get_aaa (self, obj ): return "aaa" gender = serializers.SerializerMethodField() def get_gender (self, obj ): print (obj.get_gender_display()) return obj.get_gender_display() pic = serializers.SerializerMethodField() def get_pic (self, obj ): print (obj.pic) return "%s%s%s" % ("http://127.0.0.1:8000/" , settings.MEDIA_URL, str (obj.pic))
1 2 3 4 # 总结 1. 字段类型文档: https://www.django-rest-framework.org/api-guide/fields/ 2. 序列化: 数据从数据库查出,将数据传递给序列化器进行转化成Response可以识别的类型,通过data属性可以获取到序列化后的数据,返回到前端 3. 反序列化: 数据从前端传入到视图,通过序列化器保存到数据库
反序列化
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 class EmployeeDeSerializer (serializers.Serializer): """ 反序列化: 将前端提交的数据保存到数据库 1. 需要前端提供哪些字段 2. 对字段进行安全校验 3. 有没有字段需要额外的校验 反序列化不需要自定义字段 """ username = serializers.CharField( max_length=3 , min_length=2 , error_messages={ "max_length" : "长度太长了" , "min_length" : "长度太短了" , } ) password = serializers.CharField() phone = serializers.CharField() def create (self, validated_data ): print (self) print (validated_data) return Employee.objects.create(**validated_data)
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 def post (self, request, *args, **kwargs ): request_data = request.data if not isinstance (request_data, dict ) or request_data == {}: return Response({ "status" : 400 , "message" : "参数有误" , }) serializer = EmployeeDeSerializer(data=request_data) if serializer.is_valid(): emp_ser = serializer.save() print (emp_ser) return Response({ "status" : 200 , "message" : "员工添加成功" , "results" : EmployeeSerializer(emp_ser).data }) else : return Response({ "status" : 400 , "message" : "员工添加失败" , "results" : serializer.errors })
反序列化时从前端获取的参数必须以关键字的形式EmployeeDeSerializer(data=request_data)
传递到序列化器类
通过序列化类的is_valid
对传递到序列化器的数据进行校验. 在此时才会调用序列化器为每个字段定义好的反序列化规则. 如果用过校验返回True, 失败返回False
保存失败的错误信息会包含在serializer.errors
中
通过serializer.save()
保存对象时需要重写create()
方法
作业 1 2 3 4 5 1. 掌握各个模块的作用以及使用方式 掌握源码流程 request render parser 异常处理 Response 2. 掌握DRF序列化器的使用 [重点重点] 使用序列化器完成 教师表的 查询单个 查询所有 新增单个 删除(可选)