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)
"""
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'
]
2. APIView源码分析
path('books/' , BookView.as_view()),
class BookView (APIView ):
def get (self, request ):
......
return Response(res_list)
视图类继承了APIview后,执行流程
path('books/' , BookView.as_view()),
1. 先从父类APIView中查找as_view
def as_view (cls, **initkwargs ):
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认证
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)
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
view = super ().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
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))
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__
)
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
2.3 父类APIView中的dispatch方法
class APIView (View ):
def dispatch (self, request, *args, **kwargs ):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers
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类源码分析
--原生django的request是这个类的对象:django.core.handlers.wsgi.WSGIRequest
--drf的request是这个类的对象:rest_framework.request.Request
--类中有个魔法方法:__getattr__ 对象.属性,属性不存在会触发它的执行
def __getattr__ (self, attr ):
try :
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 )
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 ()
ser = serializer.BookSerializer(
instance=book_list, 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()
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 ()
ser = serializer.BookSerializer(
instance=book_list, many=True
)
return Response(ser.data)
def post (self, request ):
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()
def update (self, 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()
ser = serializer.BookSerializer(instance=book_obj, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else :
return Response(ser.errors)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)