drf之day02:序列化组件,APIView相关知识点

一:使用View+JsonResponse写获取所有数据的接口

models.py

from django.db import models

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)

views.py

from django.views import View
from .models import Book
from django.http import JsonResponse

class BookView(View):
    def get(self, request):
        book_list = Book.objects.all()
        # 这里的book_list是queryset对象,不能直接被序列化,需要通过for循环拼成列表套字典的形式
        res_list = []
        for book in book_list:
            res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        return JsonResponse(res_list, safe=False, json_dumps_params={'ensure_ascii': False})  # 这里只能序列化列表,字典

url.py

from django.urls import path
from app01.views import BookView

urlpatterns = [
    path('books/', BookView.as_view()),
]
知识点总结:
  • 1.queryset对象是不能够直接被序列化的
  • 2.JsonResponse只能序列化列表,字典类型的数据
  • 3.safe=False: 对不是字典类型的数据序列化的时候,要把safe设置为:False
  • 4.json_dumps_params={‘ensure_ascii’: False}:能够让汉字正常显示在前端页面上

二:使用APIView+Response写获取所有数据的接口

views.py

from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        res_list = []
        for book in book_list:
            res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        return Response(res_list)  # 可以序列化字典,列表,字符串
总结:
  • 1.Response:可以序列化字典,列表,字符串
  • 2.一定要在settings.py文件中配置rest_farmework这个app

三:序列化组件的介绍及使用

drf提供了一种可以快速实现序列化的类:序列化类

序列化组件的基本使用:查询所有,查询单个

写一个序列化类

seralizers.py

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()

    # 增加数据的时候,必须重写create方法
    def create(self, validated_data):
        res = Book.objects.create(**validated_data)
        return res

    def update(self, instance, validated_data):
        """
        :param instance: 要修改的对象
        :param validated_data: 校验过后的数据
        """
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()
        return instance

views.py

from app01 import models
# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializer import BookSerializer
from .models import Book

class BooksAPIView(APIView):
    # 得到所有的数据
    def get(self, request):
        book_list = models.Book.objects.all()
        ser = BookSerializer(instance=book_list, many=True)
        return Response(ser.data)

    # 增加数据
    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

class BookDetailView(APIView):
    # 查看一条数据
    def get(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)

    # 修改一条数据
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

    # 删除一条数据
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response()

urls.py

from django.urls import path
from app01.views import BooksAPIView, BookDetailView

urlpatterns = [
    path('books/', BooksAPIView.as_view()),
    path('books/<int:pk>/', BookDetailView.as_view()),
]
总结:
  • 1.视图类方法中的instance是queryset对象,表示要序列化的数据
  • 2.many=True:表示序列化多条
  • 3.序列化类有数据校验功能
  • 4.前端传的数据,从request.data中获取
  • 5.ser.save() 调用save会触发BookSerializer的save方法,判断了,如果instance有值执行update,没有值执行create

四:APIView源码分析

1.从视图类的as_view着手

path('books/', BooksAPIView.as_view()),

2.去自己定义的视图类中查找,发现没有as_view方法

3.那就去父类(APIView)中查找,as_view方法的返回值是:csrf_exempt(view),所以:所有的请求都没有csrf的校验了

 @classmethod
def as_view(cls, **initkwargs):
     # 又调用了父类(View)的as_view
     view = super().as_view(**initkwargs)			
     return csrf_exempt(view) # 所有的请求都没有csrf的校验了

4.请求来了,路由匹配成功会执行 View类的as_view方法内的view闭包函数(没有csrf认证)

5.真正执行的还是:APIView中的self.dispatch方法**[重点]**

    def dispatch(self, request, *args, **kwargs):
        # 参数的request是原来的django原生的request
        
        # 下面的request,变成了drf提供的Request类的对象
        request = self.initialize_request(request, *args, **kwargs)
        
        # self是视图类的对象,视图类对象.request = request 新的request
        self.request = request
        
        self.headers = self.default_response_headers  # deprecate?

        try:
            # 下面这段代码执行了认证,频率,权限
            self.initial(request, *args, **kwargs)
			
            # 这是原来View类的dispatch方法
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            # 如果除了异常,捕获异常,正常返回
            response = self.handle_exception(exc)
		# 在执行三大认证,视图类中的方法的时候,出现异常,是能够被异常捕获,并被处理的
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
总结:
  • 1.只要继承了APIView,都没有csrf的认证
  • 2.视图类中使用的request对象,已经变成了drf提供的Request类的对象了
  • 3.执行视图类的方法之前,执行了3大认证(认证,权限,频率)
  • 4.在执行三大认证和视图类的方法过程中,只要报错,都会被捕获处理

五:Request类源码分析

1.原生的django的request对象的类:
django.core.handlers.wsgi.WSGIRequest
2.drf的request对象的类:
est_framework.request.Request
3.request不是以前的request,但是用起来还是和原先一样
request.method
request.path
request.GET
request.POST
4.Request源码分析
    def __getattr__(self, attr):
        """
        如果取的属性不存在,会去原生的django的request对象中去取
        If an attribute does not exist on this instance, then we also attempt
        to proxy it to the underlying HttpRequest object.
        """
        try:
            # request._request  就是原来的原生的request
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)
print(type(request._request))  # django.core.handlers.wsgi.WSGIRequest
总结:
  • 1.新的request内有一个老的request,就是:request._request
  • 2.data 是一个方法,被property装饰了,变成了属性
  • 3.以后body中提交的数据,都从request.data中取,原先是从(request.POST)
  • 4.-urlencoded,form-data:提交的数据在request.POST中
  • 5.-json格式提交的数据,在requets.POST中没有,它在request.body中
  • 6.以后无论哪种数据类型,都从request.data中取
  • 7.取文件,还是从request.FILES中取
  • 8.query_params:get请求提交的参数,等同于request._request.GET 或 request.GET
  • 9.以后用的所有属性或方法,直接用就可以了(通过反射去原来的request中取的)

作业1:

1 继承apiview写5个接口

class BookView(APIView):
    # 查看所有数据
    def get(self, request):
        book_list = Book.objects.all()
        res_list = []
        for book in book_list:
            res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        return Response(res_list)  # 可以序列化字典,列表,字符串

        # 增加数据

    def post(self, request):
        name = request.data.get('name')
        price = request.data.get('price')
        publish = request.data.get('publish')

        if Book.objects.create(name=name, price=price, publish=publish):
            res_list = [{'name': name, 'price': price, 'publish': publish}]
            return Response(res_list)


class BookDetailView(APIView):
    # 查看一条数据
    def get(self, request, pk):
        book_list = Book.objects.filter(pk=pk).all()
        res_list = []
        for book in book_list:
            res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        return Response(res_list)

    # 修改一条数据
    def put(self, request, pk):
        name = request.data.get('name')
        price = request.data.get('price')
        publish = request.data.get('publish')
        Book.objects.filter(pk=pk).update(name=name, price=price, publish=publish)
        book_list = Book.objects.filter(pk=pk).all()
        res_list = []
        for book in book_list:
            res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        return Response(res_list)

    # 删除一条数据
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response()

作业2:

2.写一个装饰器,装饰在视图函数,只要一装饰,以后的request就可以使用request.data,这个data无论是那种编码格式,都有数据。

import json


def outer(func_name):
    def inner(request, *args, **kwargs):
        try:
            request.data = json.loads(request.body)
        except:
            request.data = request.POST
        res = func_name(request, *args, **kwargs)
        return res
    return inner

@outer
def func(request):
    print(request.data)
    return JsonResponse({})

urls.py

path('func/', views.func),
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值