APIView的使用,API源码,Request源码,序列化组件
-
APIview的基本使用
-
View+JsonResponse和APIView+drf的Response编写接口
-
View+JsonResponse编写接口
-
APIView+drf的Response编写接口
-
-
-
API源码分析
-
Request类源码分析
-
序列化组件
-
反序列化
APIview的基本使用
View+JsonResponse和APIView+drf的Response编写接口
定义字段models.py
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
View+JsonResponse编写接口
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
1. 在这里我们的BookView类继承的是View这个类,使用JsonResponse序列化
2. queryset对象是不能直接序列化的 需要通过列表的方式追加成列表套字典的形式
3. JsonResponse只能序列化字典和列表
# 视图类
from django.http import JsonResponse
from django.views import View
from .models import Book
class BookView(View):
def get(self,request):
book_list = Book.objects.all() # book_list是queryset对象,不能直接序列化,需要通过列表的方式一个个追加拼成列表套字典的形式
res_list = []
for book in book_list:
res_list.append({'name':book.name,'price':book.price,'publish':book.publish})
print(res_list)
# [{'name': '西游记', 'price': '200 ', 'publish': '东方出版社'}, {'name': '三国', 'price': '400', 'publish': '西方出版社'}]
return JsonResponse(res_list,safe=False,json_dumps_params={'ensure_ascii':False}) # JsonResponse只能序列化字典和列表
APIView+drf的Response编写接口
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 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)
settings.py
记得在settings中注册rest_framework
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'rest_framework' # 不要忘记注册rest_framework这个app 如果不注册会报错 注册后会显示drf特有的页面
]
API源码分析
视图类继承了APIView之后,执行顺序就会发生变化,这个变化就是drf的整个执行流程
1. 匹配路由>>>找到视图类的as_view(但是这里是APIView的as_view)
APIView中的as_view方法---主要代码(删减版)
csrf_exempt()
@csrf_exempt 装饰器
@classmethod
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs) # 这里调用了APIView的父类(View)也就是视图类的爷类(View)的as_view方法
return csrf_exempt(view) # csrf_exempt解除csrf的校验
2. 请求来了以后,路由匹配成功会执行 View里面的as_view闭包函数中的view(没有了csrf的校验),但是真正执行的是view里面的self.dispatch方法(APIView中的dispatch方法) --- 因为self是视图类 所以self.dispatch还是要从视图类开始找
View中的as_view
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
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
return view
视图类函数(BookView)的父类(APIView)的dispatch方法
1. 其中initlize_request返回了一个 drf提供的一个Request类的对象 return Request(。。。)
所以说视图类中的参数request,经过APIView中的dispatch中的initlize_request()操作变成了drf提供的Request类的对象
def dispatch(self, request, *args, **kwargs):
# 上面的request参数还是django原来的request
self.args = args
self.kwargs = kwargs
# 下面的request经过initlize_request()操作变成了drf提供的Request类的对象
request = self.initialize_request(request, *args, **kwargs)
# 之后的request不再是django原来的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
initialize_request 返回了一个Request对象
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
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
)
总结:
1. 只要继承了APIView都没有csrf的认证
2. 以后的视图类中的request不再是原来的request对象,已经变成了drf提供的Request对象
因为视图类中的参数request,经过APIView中的dispatch中的initlize_request()操作变成了drf提供的Request类的对象
3. 执行视图类的方法之前都会先执行三大认证(认证,权限,频率)
4. 在执行视图类的方法和三大认证只要报错,都会被捕获处理
流程:
---路由匹配
---成功执行as_view()
---先到APIView中找到as_view(),发现它用了super()
---所以到View中找as_view(),在as_view()里面有一个闭包函数,所以看as_view()里面的view()
---在view()里面有一个self.dispatch()方法,由于self是视图类,所以要从视图类再开始找,视图类中没有到他的父类APIView中找到dispatch(),在dispatch中有一个initlize_request()将django原来的request变成了drf提供的Request对象里面还包含了三大认证和异常捕获处理
Request类源码分析
验证视图类中的request还是不是原来的request
答:NO
执行下面的代码
print(request)
print(type(request))
Django原来的request对象
<WSGIRequest: GET '/books/'>
<class 'django.core.handlers.wsgi.WSGIRequest'>
继承了APIView的request对象
<rest_framework.request.Request: GET '/books/'>
<class 'rest_framework.request.Request'>
request不是原来的request了,还能像原来一样使用吗
答:YES,原来怎么用,现在还是怎么用 (是因为__getattr__方法,下面会说)
print(request.GET)
print(request.POST)
........
Request源码分析
from rest_framework.request import Request
在Request源码中有一个__getattr__的方法:对象.属性当属性不存在的时候会自动触发该方法
def __getattr__(self, attr): # 当属性不存在的时候自动触发
try:
#反射:根据字符串获取属性或方法,self._request 是原来的request
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
(由此克制我们上面用的request方法并非自己的,而是通过Request中的__getattr__中的反射去原来的request中调用的)
在新的request中有个老的request:_request

data
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
1. urlencoded,form-data:提交的数据在request.POST中
2. 在request.POST中如果是json格式上传,request.POST是拿不到的,要在request.body中取到

但是request.data是万能的

request.data文件也可以拿
request.FILES
request.data 拿到的是所有

request.data 有时候是(urlencoded,form-data)QueryDict,有时候(json)是字典
序列化组件
1. 序列化组件就是drf提供的一个类(),我们可以继承它,改写
2. 它的作用就是用来序列化queryset或者单个对象的
定义一个序列化类
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
# 定义需要序列化的字段
# 定义的字段类型要根据你在models中创建的字段类型来
name=serializers.CharField()
price = serializers.CharField() # 如果不想显示直接注释掉就好
publish = serializers.CharField()
使用序列化类序列化多条数据
1. instance表示要序列化的数据
2. many=True表示序列化多条(instance是qs对象,一定要传many=True)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from serializer import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ser = BookSerializer(instance=book_list, many=True)
return Response(ser.data)
使用序列化类序列化一条数据
1. 要给出确定的pk值(就是那一条数据)
2. many = True去掉
urls.py
from app01.views import BookDetailView
urlpatterns = [
path('admin/', admin.site.urls),
path('book/<int:pk>/',BookDetailView.as_view())
]
views.py
class BookDetailView(APIView):
def get(self,request,pk):
book = Book.objects.all().filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response(ser.data)

反序列化
urls.py
from django.contrib import admin
from django.urls import path
from app01.views import BookView,BookDetailView
urlpatterns = [
path('admin/', admin.site.urls),
path('books/',BookView.as_view()),
path('books/<int:pk>/',BookView.as_view()),
path('book/<int:pk>/',BookDetailView.as_view())
]
新增
NotImplementedError: `create()` must be implemented. 这句报错的意思是create要被重写才能执行
class BookView(APIView): # APIView继承自django的View
def post(self, request):
# 前端传递数据,从request.data取出来
ser = BookSerializer(data=request.data)
if ser.is_valid(): # 表示校验前端传入的数据 没有写校验规则,现在等于没校验
ser.save() # 再写东西,这里会报错 调用save会触发BookSerializer的save方法,判断了,如果instance有值执行update,没有值执行create
return Response(ser.data)
else:
return Response(ser.errors)
看save的源码
def save(self, **kwargs):
# 如果self.instance 没有值就会执行self.create(validated_data)
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
return self.instance
self.create(validated_data)
所以这里才会报这个错
def create(self, validated_data):
raise NotImplementedError('`create()` must be implemented.')
解决: 在我们的serilizer中重写create方法
def create(self, validated_data):
res = Book.objects.create(**validated_data)
return res
修改
1. 获取pk值
2. 前端传递数据,从request.data取出来
class BookDetailView(APIView):
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)
改写put方法
1.instance要修改的对象
2.validated_data 校验过后的数据
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.save()
return instance
delete直接删
class BookDetailView(APIView):
def delete(self, request, pk):
book = Book.objects.filter(pk=pk)
book.delete()
return Response()
get查询
查询单条
class BookDetailView(APIView):
def get(self, request, pk):
book = Book.objects.all().filter(pk=pk).first()
bookSerializer = BookSerializer(instance=book,)
print(book)
res = bookSerializer.data
return Response(res)
或者
class BookView(APIView):
def get(self, request, pk):
book = Book.objects.all().filter(pk=pk).first()
bookSerializer = BookSerializer(instance=book)
print(book)
res = bookSerializer.data
return Response(res)
查询多条
class BookDetailView(APIView):
def get(self, request, pk):
book = Book.objects.all().filter(pk=pk)
bookSerializer = BookSerializer(instance=book,many=True)
print(book)
res = bookSerializer.data
return Response(res)

浙公网安备 33010602011771号