内容概览
- APIView基本使用
- APIView源码分析
- Request类源码分析
- 序列化组件介绍
- 序列化组件基本使用
- 反序列化
APIView基本使用
- drf是一个第三方的app,只能够在django上使用
- 安装后需要在setting中注册这个app:rest_framework
- 安装了drf后,在views中导入视图类APIView,所有后期要是用drf写视图类,都是继承APIView及其子类
使用View+JsonResponse写获取所有图书接口
class BookView(View)
def get(request):
books = models.Book.objects.all()
book_list = [] # JsonResponse不能够直接序列化Queryset对象
for book in books:
book_list.append({'title':book.title,'price':book.price,'publish':book.publish}) # 将每本书的数据以字典的形式追加到列表中
return JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii':False}) # safe=False才能够序列化列表
使用APIView+Response写获取所有图书接口
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
books = models.Book.objects.all()
book_list = []
for book in books:
book_list.append({'title': book.title, 'price': book.price, 'publish': book.publish})
return Response(book_list)
APIView源码分析
"""还是先找视图类的as_view方法,自身没有去父类APIView找"""
@classmethod
def as_view(cls, **initkwargs):
# 又调用了父类(View)的as_view
view = super().as_view(**initkwargs)
return csrf_exempt(view)
"""
返回值等同于
index=csrf_exempt(index) 装饰器原理
return index
csrf_exempt是取消校验csrf的装饰器,代表以后所有请求都不会校验csrf了
"""
"""请求来了以后,会执行dispatch方法,还是从自身开始查询,然后是APIView
所以真正执行的是APIView的dispatch"""
def dispatch(self, request, *args, **kwargs):
# 参数的request是原来的django原生的request
# 下面的request,变成了drf提供的Request类的对象---》return Request(。。。)
request = self.initialize_request(request, *args, **kwargs)
# self 是视图类的对象,视图类对象.request=request 新的request
self.request = request
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类源码分析
"""在调用dispatch方法的时候执行了一个方法使request变成了drf提供的Request类的对象"""
def initialize_request(self, request, *args, **kwargs):
return Request(request,...)
class Request:
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self._request = request
"""
将原来的request存在_reqeust中
但还是能和之前的request一样使用
原因是Request中使用了__getattr__魔法方法:当点的属性不存在时触发
"""
def __getattr__(self, attr):
try:
return getattr(self._request, attr) # 如果不存在去原来的request中获取
except AttributeError:
return self.__getattribute__(attr)
"""
Request类中有一个data方法,被property装饰了,可以直接当做属性调用
以后body体中提交的数据,都可以从这里取到(request.POST)
urlencoded/form-data提交的数据在request.POST中,Json格式提交的数据在request.body中
三种数据格式都可以在request.data中取到
query_params:get请求提交的参数,等同于request.GET
文件还是在reqeust.FILES中获取
"""
序列化组件介绍
序列化组件是什么:drf提供的一个类,我们继承它,写自己的类
序列化组件的作用:可以快速实现序列化
序列化组件基本使用
定义一个序列化类
"""创建一个py文件,编写序列化类给book进行序列化"""
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title = serializers.CharField() # 需要序列化的字段
price = serializers.CharField()
publish = serializers.CharField()
使用序列化类,序列化多条数据
from app01.serializers import BookSerializer # 先导入类
class BookView(APIView):
def get(self, request):
books = models.Book.objects.all()
bs = BookSerializer(instance=books, many=True) # instance代表序列化的数据,如果是多条数据(queryset对象),需要使用many=True表示序列化多条数据
return Response(bs.data)
使用序列化类,序列化单条数据
class BookDetailView(APIView):
def get(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
bs = BookSerializer(instance=book)
return Response(bs.data)
反序列化
系列化类也有数据校验功能
新增
views.py:
def post(self, request):
bs = BookSerializer(data=request.data)
if bs.is_valid(): # 校验数据
bs.save() # 调用save会触发BookSerializer的save方法,判断,如果生成类的时候instance有值执行update,没有值执行create
return Response(bs.data) # 根据规范,返回新增对象数据
else:
return Response(bs.errors) # 返回错误信息
只写上述代码会报错,需要重写create方法
serializers.py:
class BookSerializer(serializers.Serializer):
title = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
def create(self, validated_data):
res = models.Book.objects.create(**validated_data)
return res
修改
views.py:
def put(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
bs = BookSerializer(instance=book, data=request.data)
if bs.is_valid(): # 校验数据
bs.save() # 调用save会触发BookSerializer的save方法,判断,如果生成类的时候instance有值执行update,没有值执行create
return Response(bs.data) # 根据规范,返回修改对象数据
else:
return Response(bs.errors) # 返回错误信息
修改也需要重写update方法
serializers.py:
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.save()
return instance
删除
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).delete()
return Response() # 返回空
了解
1 http协议版本区别
1. http/0.9:只有GET命令,服务器只能回应HTML格式字符串
2. http/1.0:每个TCP连接只能发送一个请求,还要发送请求需要再次连接
3. http/1.1:可以持久连接,TCP连接默认不关闭,可以被多个请求复用;keep-alive
4. http/2:复用TCP协议,在一个连接里客户端与浏览器都可以同时发送多个请求或回应,不用按照顺序一一对应
2 http请求头有哪些
1. Accept:设置接受的内容类型
2. Accept-Charset:设置接受的字符编码
3. Accept-Encoding:设置支持的内容编码的优先级顺序
4. Accept-Language:设置接受的语言
5. Connection:设置当前事务完成后,是否会关闭网络连接
6. Connection-Length:设置请求体的字节长度
7. Content-Type:设置请求体的MIME类型
8. referer:包含了当前请求页面的来源页面地址
9. Cookie:设置服务器使用set-cookie发送的http cookie
练习
1 继承apiview写5个接口
urls.py:
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
使用APIView
views.py:
from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book = models.Book.objects.all()
bs = BookSerializer(instance=book, many=True)
return Response(bs.data)
def post(self, request):
bs = BookSerializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
class BookDetailView(APIView):
def get(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
bs = BookSerializer(instance=book)
return Response(bs.data)
def put(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
bs = BookSerializer(instance=book, data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).delete()
return Response()
serializers.py:
from rest_framework import serializers
from app01 import models
class BookSerializer(serializers.Serializer):
title = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
def create(self, validated_data):
res = models.Book.objects.create(**validated_data)
return res
def update(self, instance, validated_data):
instance.title = validated_data.get('title')
instance.price = validated_data.get('price')
instance.publish = validated_data.get('publish')
instance.save()
return instance
不使用APIView
views.py:
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django import views
from app01 import models
from app01.MyForms import Forms_book
class BookView(views.View):
def get(self, reqeust):
books = models.Book.objects.all()
book_list = [] # JsonResponse不能够直接序列化Queryset对象
for book in books:
book_list.append({'title': book.title, 'price': book.price, 'publish': book.publish}) # 将每本书的数据以字典的形式追加到列表中
return JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii': False}) # safe=False才能够序列化列表
def post(self, request):
data_dict = json.loads(request.body)
form_obj = Forms_book(data_dict)
if form_obj.is_valid():
data = form_obj.cleaned_data
models.Book.objects.create(**data)
return JsonResponse(data)
else:
return JsonResponse(form_obj.errors)
class BookDetailView(views.View):
def get(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
return JsonResponse({'title':book.title,'price':book.price,'publish':book.publish})
def put(self, request, pk):
data_dict = json.loads(request.body)
form_obj = Forms_book(data_dict)
if form_obj.is_valid():
data = form_obj.cleaned_data
models.Book.objects.filter(pk=pk).update(**data)
return JsonResponse(data)
else:
return JsonResponse(json.dumps(form_obj.errors))
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).delete()
return HttpResponse()
MyForms.py:
from django import forms
class Forms_book(forms.Form):
title = forms.CharField(max_length=12)
price = forms.CharField(max_length=4)
publish = forms.CharField(max_length=32)
2 fbv写——>写个装饰器,装饰在视图函数,只要一装饰,以后的request就可以使用request.data,这个data无论是那种编码格式,都有数据
def outer(func_name):
def inner(request, *args, **kwargs):
if request.POST:
request.data = request.POST
else:
data_dict = json.loads(request.body)
request.data = data_dict
res = func_name(request, *args, **kwargs)
return res
return inner