APIView基本使用

APIView

1. APIView基本使用

drf是一个第三方的app,只能在django中使用
安装了drf后,导入一个视图类APIView,所有后期需要使用drf写的视图类,都是继承APIView及其子类

	

1.1 使用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)
        author = models.CharField(max_length=32)
        publish = models.CharField(max_length=32)
        
        
# 路由
urls.py
	from django.contrib import admin
	from django.urls import path
	from app01.views import BookView

	urlpatterns = [
    	path('admin/', admin.site.urls),
    	path('books/', BookView.as_view()),
		]

# 写视图类
Views.py
	from django.shortcuts import render, HttpResponse
	from django.views import View
	from app01 import models
	from django.http import JsonResponse


	class BookView(View):
    	def get(self, request):
        	book_list = models.Book.objects.all()
             print(book_list)  # <QuerySet [<Book: Book object (1)>]>
        # 错误方式
        """
        
         return JsonResponse(book_list) # book_list是queryset对象
         				不能直接序列化,只能通过for循环拼成列表套字典的方式
        否则报错:
            TypeError: In order to allow non-dict
                        objects to be serialized set the safe parameter to False.
        
        """
        # 正确方式
        res_list = []
        for i in book_list:
            res_list.append({'name': i.name, 'price': i.price, 'publish': i.publish, 'author': i.author})
        return JsonResponse(res_list, safe=False, json_dumps_params={'ensure_ascii': False})  # 只能序列化字典和列表,
        

1.2 使用APIView的Response

views.py
	from rest_framework.views import APIView
	from rest_framework.request import Request
	from rest_framework.response import Response


	class BookView(APIView):
   		def get(self, request):
        	book_list = models.Book.objects.all()
        	res_list = []
        	for i in book_list:
            	res_list.append({'name': i.name, 'price': i.price, 'publish': i.publish, 'author': i.author})
        	return Response(res_list)

settings.py
	settings.py中注册
    
    	INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework'  # 注册这个drfapp
]

2. APIView源码分析

# urls.py
	 path('books/', BookView.as_view()),
	 
# views.py
	class BookView(APIView):
    	def get(self, request):
  			......
        	return Response(res_list)

视图类继承了APIview后,执行流程
path('books/', BookView.as_view()),
# 父类(APIView)中的as_view
	1.先从父类APIView中查找as_view
		def as_view(cls, **initkwargs):
# 父类APIView的父类(View)的as_view
	2.父类APIView中的as_view又调用了APIView父类View的as_view方法
		view = super().as_view(**initkwargs)
	3. 父类View的as_view方法调用自身的闭包函数view返并返回view
		return view 
    4. 通过csrf_exempt取消了csrf认证
    	# 从此以后继承APIView的视图类,所有的请求都没有csrf的校验了
    	return csrf_exempt(view)
    
    5. 请求来了之后执行父类View的as_view方法中的闭包函数view
    	def view(request, *args, **kwargs):
    		return self.dispatch(request, *args, **kwargs)
	6.view方法最后返回了一个dispatch方法
		self.dispatch(request, *args, **kwargs)
# 父类APIView中的dispatch方法
	7.从自身查找找到父类APIView中的dispatch方法
		def dispatch(self, request, *args, **kwargs):
	7.dispatch方法调用initialize_request方法将request对象重新封装成一个新的request对象
		request = self.initialize_request(request, *args, **kwargs)
    	self.request = request
     8.使用try
    	try:
           8.1通过self.initial(request, *args, **kwargs)三大认证模块,执行了认证,频率,权限
            self.initial(request, *args, **kwargs)
            8.2判断转为小写的request.method请求是否在八个请求内
            if request.method.lower() in self.http_method_names:
                8.2.1如果在通过反射获取视图类中与之相对于的属性或方法
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            8.3 执行后并赋值给response
            response = handler(request, *args, **kwargs)
        except Exception as exc:
            8.4 如果出现异常,捕获异常,处理异常,正常返回
            response = self.handle_exception(exc)
	9.最后正常返回
    	return self.response

2.1 父类(APIView)中的as_view

class APIView(View):
	@classmethod
    def as_view(cls, **initkwargs):
        if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
            def force_evaluation():
                raise RuntimeError(
                    'Do not evaluate the `.queryset` attribute directly, '
                    'as the result will be cached and reused between requests. '
                    'Use `.all()` or call `.get_queryset()` instead.'
                )
            cls.queryset._fetch_all = force_evaluation
		# 调用了APIView父类View的as_view方法
        view = super().as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs
        # 通过csrf_exempt取消了csrf认证
        # 以后所有的请求,都没有csrf认证了,只要继承了APIView就没有csrf的校验了
        return csrf_exempt(view)

2.2 父类APIView的父类(View)的as_view

class View:
	@classonlymethod
    def as_view(cls, **initkwargs):
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))
		# 执行view
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            # 返回self.dispatch(request, *args, **kwargs)
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs
        update_wrapper(view, cls, updated=())
        update_wrapper(view, cls.dispatch, assigned=())
        return view  # 返回View类中as_view方法内的view闭包函数

2.3 父类APIView中的dispatch方法

class APIView(View):
    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        # 调用initialize_request方法将原生的django的request对象重新封装成一个新的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)
            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
    

    def initialize_request(self, request, *args, **kwargs):
        parser_context = self.get_parser_context(request)
        return Request(request,parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

3. Request类源码分析

# 视图类中使用request对象,已变成了drf提供的Request类的对象了
	--原生django的request是这个类的对象:django.core.handlers.wsgi.WSGIRequest
	--drf的request是这个类的对象:rest_framework.request.Request
# request已经不是原来的request了,用起来跟之前一样
# Request的源码分析:rest_framework.request.Request
	--类中有个魔法方法:__getattr__ 对象.属性,属性不存在会触发它的执行
        def __getattr__(self, attr):  # 如果取的属性不存在回去原生django的request对象中取出
        try:
            # 反射: 根据字符串获取属性或方法,self._request 是愿挨的request
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)
	
    --以后用的所有属性或方法,直接用就可以了(通过反射取原来的request中取的)
	--新的request内部有个老的request,就是request._request
    
    
    --以前
    	urlencoded,form-data提交的数据在request.POST
   		json格式提交的数据,在request.post中没有,它在request.body中
    
    --data 是个方法,被porperty装饰了,变成了数据属性用
    	以后无论上述的那种格式,都从request.data中取
        from-data提交的数据 在request.data中
        	<QueryDict: {'name': ['golang'], 'price': ['123'], 'publish': ['北方出版社'], 'author': ['tony123']}>
         urlencoded提交的数据,在request.data中
        	<QueryDict: {'name': ['linux'], 'price': ['8888'], 'publish': ['东方出版社'], 'author': ['tony456']}>
         json格式提交的数据,在request.data中
        	{'name': 'mysql', 'price': '9999', 'publish': '上海出版社', 'author': 'tony789'}
	--query_params:get请求提交的参数,等同于request._request.GET或request.GET
    --其它:取文件也是从request.FILES中取,跟之前一样。
    
    # 验证
    	原生request.POST 只有urlencoded和form-data格式提交的数据。
        json格式提交的数据在body中,需要自己拿出来自己处理
        
        但drf的request中有个data
        	data中可以渠道任意编码提交的数据
            request.data 有时候是urlencoded,from-data取出来的是QueryDict
            
            有时候json 其取出来的直接是字典形式
            
    # 什么是魔法方法
    	在类中只要以__开头,__结尾的都称之魔法方法
        这种方法不需要手动调用,某种情况下会自动触发

4. 序列化组件介绍

序列化组件时drf提供的一个类,继承它写自己的类
	通过它来序列化qs或单个对象
    
drf提供了一种可以快速实现序列化类:

4.1 定义一个序列化类

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


# 新建一个py文件serializer,写序列化类:给book进行序列化
serializer.py
	from rest_framework import serializer
    	class BookSerializer(serializer.Serializer):
            """继承Serializer"""
            # 写需要序列化的字段,有很多字段类,字段类又很多的字段属性
            name = serializer.CharField()  
            price = serializer.CharField()
            publish = serializer.CharField()
            author = serializer.CharFiels()

4.2 序列化类,序列多条数据

views.py

	from app01 import serializer

	class BookView(APIView):
    	def get(self, request):
        	book_list = models.Book.objects.all()
        	# instance 表示要序列化的数据
        	# many=True表示序列化多条
        	ser = serializer.BookSerializer(
            	instance=book_list, many=True
        	)  # instance时qs对象,一定要传many=True
        	return Response(ser.data)

4.3 序列化类,序列化单条

urls.py
	 path('books/<int:pk>', views.BookOneView.as_view()),

views.py
	from app01 import serializer
    
	class BookOneView(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        ser = serializer.BookSerializer(instance=book_obj)
        return Response(ser.data)

5. 反序列化(新增,修改,删除)

5.1 新增数据

serializer.py 序列化类中
	class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()
    author = serializers.CharField()
	# 重写create方法
    def create(self, validated_data):
        res = models.Book.objects.create(**validated_data)
        return res



views.py  视图类中
	class BookView(APIView):
    def get(self, request):
        book_list = models.Book.objects.all()
        # instance 表示要序列化的数据
        # many=True表示序列化多条
        ser = serializer.BookSerializer(
            instance=book_list, many=True
        )  # instance时qs对象,一定要传many=True

        return Response(ser.data)

    def post(self, request):
        # 前端传递的数据,从request.data中取出来
        ser = serializer.BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)





5.2 修改数据

serializer.py 序列化类中
	class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()
    author = serializers.CharField()

 	# 重写update
    def update(self, instance, validated_data):
        # instance需要修改的对象
        # validated_data 校验过后的对象
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.author = validated_data.get('author')
        instance.save()
        # 最后将修改后的对象返回出去
        return instance


views.py  视图类中
	class BookOneView(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        ser = serializer.BookSerializer(instance=book_obj)
        return Response(ser.data)

    def put(self, request, pk):
        # 将前端传来的数据赛选出需要修改的对象
        book_obj = models.Book.objects.filter(pk=pk).first()
        # instance=book_obj, 表示需要修改的对象,
        # data=request.data 表示需要修改的数据
        ser = serializer.BookSerializer(instance=book_obj, data=request.data)
        #  调用save会触发BookSerializer的save方法,判断了,如果instance有值执行update,没有值执行create
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)


posted @   瓮小辉  阅读(141)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示