基于APIView+Response 写接口
在views.py中
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
class BookView(APIView): # 使用cbv方法编写 继承APIView
def get(self,request):
book_list = []
books = Book.objects.all() # 拿到所有数据对象
for book in books:
book_list.append({'name':book.name,'price':book.price})
# 把数据对象转为字典 添加入一个列表
return Response(book_list)
# 使用drf内Response模块,可以直接将字典或列表序列化
分析APIView执行流程
from rest_framework.views import APIView
from rest_framework.response import Response
path('books/', views.BookView.as_view())
1.APIView的as_view方法执行:view还是原来的view,但是去掉了csrf的认证
当请求来了的时候会执行views.BookView.as_view()这个方法,因为BookView类本身没有as_view()方法,所以从父类里面查找,查到了APIView里面的as_view方法并执行了
@classmethod
# 类方法 调用父类的as_view
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs)
# super是从父类中拿as_view(**initkwargs)方法并执行
# 执行后获得了原生django中as_view中闭包函数view拿出来了
return csrf_exempt(view)
# csrf_exempt 排除所有请求的csrf认证
# 最后相当于把原生view排除了所有csrf认证
2.路由匹配成功相当于执行了 csrf_exempt(view)(request),本质还是原生的view执行了self.dispatch
self是视图类对象(bookview对象由于bookview对象中没有dispatch方法,所以就从父类中找 APIView中找到了dispatch方法
def dispatch(self, request, *args, **kwargs):
request = self.initialize_request(request, *args, **kwargs)
# 在这里把原来的request包装成了新的request
# 通过initialize_request方法看到把老的request放入了request._request中
self.request = request
# 把新的request放到了视图类的对象中
try:
# 开启异常捕获
self.initial(request, *args, **kwargs)
# 执行三大认证 认证 频率 权限
if request.method.lower() in self.http_method_names:
# 判断请求方式 是否在 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.先去除了所有请求的csrf认证
2.包装了新的request 以后视图类中的request是新的了老的request在
新的request._request里面
3.在执行视图类方法之前 先进行了3大认证
4.如果在执行3大认证或执行过程中出错 会有异常捕获
request源码分析
from rest_framework.request import Request
新的request中包含了老的 request._request就是老的
Request源码中:
def __getattr__(self, attr):
# __getattr__魔法方法:对象.属性如果该属性不存在则触发
# request.get由于新的request中没有.method方法所以会触发这个魔法方法
try:
return getattr(self._request, attr)
# 当这个方法被触发 就返回了老的request中的该方法
except AttributeError:
return self.__getattribute__(attr)
1.新的request用起来跟老的一样,是因为新的方法取不到就会默认取老的request的方法、
2.以后不管是什么数据,都从request.data中取,取出来就是字典
3.rul中携带的参数get请求携带的参数,以后从request.query_params中取
4.文件还是从request.FILES中取
class BookView(APIView):
def get(self, request):
print(self.request.data)
print(self.request.query_params)
print(self.request.FILES)
序列化组件(查询)
查询所有接口
首先创建序列化类
新建serializer.py文件:
from rest_framework import serializers
# 需要导入这个类 继承这个类
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
# 写法导致跟models类相同
price = serializers.CharField()
publish = serializers.CharField()
# 需要序列化的字段数据,这里写什么就会自动序列化什么,如果有表中不想展示的字段,
# 这里可以不写那个字段
path('books/', views.BookView.as_view()),
views.py中
创建类方法 get请求获取所有数据
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
# 获得所有数据对象 queryset列表
ser = BookSerializer(instance=books, many=True)
# 把数据对象列表交给我们创建的序列化类进行处理,instance=需要序列化的数据
# many=是否是多个数据,如果是单个数据对象不需要many属性
return Response(ser.data)
# 直接把序列化好的数据返回,序列化好的数据在ser.data中
查询单个数据接口
查询单个url需要携带参数
path('books/<int:id>', views.BookOneView.as_view()),
views.py中
class BookOneView(APIView):
def get(self, request, id):
book = Book.objects.filter(pk=id).first()
ser = BookSerializer(instance=book)
# 由于book是单个数据 不需要many属性设置 默认many=False
return Response(ser.data)
反序列化组件(新增/修改)
新增
序列化文件中serializer.py中
添加类方法
path('books/', views.BookView.as_view()),
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
def create(self, validated_data):
book_obj = Book.objects.create(**validated_data)
return book_obj
# 创建create方法 并返回创建的对象
views.py视图类中添加post请求方法
class BookView(APIView):
def post(self,request):
ser = BookSerializer(data=request.data)
# 将序列化类中的数据改为request.data
# request.data就是通过校验前端传来的数据
if ser.is_valid():
# 当数据通过校验 直接保存
ser.save()
# 执行.save方法 该方法中会调用对象本身的create方法
# 我们通过序列化类产生了一个对象,然后用这个对象调用create方法
# 就是调用了序列化类里面的create方法我们刚刚写的
return Response({'code':100,'msg':'新增成功'})
else:
return Response({'code':101,'msg':ser.errors})
修改:
path('books/<int:id>', views.BookOneView.as_view()),
views.py视图类中添加put请求方法
class BookOneView(APIView):
def put(self,request,id):
book = Book.objects.filter(pk=id).first()
# 拿到数据对象
ser = BookSerializer(instance=book,data=request.data)
# 数据对象传入序列化类中,instance=需要修改的数据 data=前端传过来的数据
# 产生一个新的数据对象
if ser.is_valid():
ser.save()
# 执行.save()方法,其中通过判断是否有instance属性来判断是执行 create
# 还是执行updata 有执行了updata
return Response({'code':100,'msg':'修改成功'})
else:
return Response({'code':101,'msg':ser.errors})
在序列化类中添加 updata方法:
def update(self, instance, validated_data):
# instance=需要修改的对象 我们之前传的book
# validated_data 前端的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.publish = validated_data.get('publish')
instance.save()
# 更改过后对象进行保存
return instance
# 记得然后在返回出去
删除资源
不涉及序列化或反序列化
class BookOneView(APIView):
def delete(self,request,id):
res = Book.objects.filter(pk=id).first()
if not res:
return Response({'code': 103, 'msg': '该文件不存在'})
res = Book.objects.filter(pk=id).first().delete()
if res:
return Response({'code':102,'msg':'删除成功'})
反序列化的校验
反序列就是 新增 和 修改 等写入数据库的动作
在序列化的类中添加钩子函数做校验
主动抛异常需要导入函数
from rest_framework.validators import ValidationError
class BookSerializer(serializers.Serializer):
# 序列化某些字段,这里写要序列化的字典
name = serializers.CharField() # serializers下大致跟models下的类是对应的
price = serializers.CharField()
publish = serializers.CharField()
# 局部钩子 name字段
def validate_name(self, name):
if len(name) < 3:
# 对name字段做限制
raise ValidationError('书名须大于3位数')
# 主动抛异常
else:
return name
# 没有问题还把这个字段反出去
# 全局钩子
def validate(self, attrs):
if attrs.get('name') == attrs.get('publish'):
raise ValidationError('书名和出版社名称不能一致')
else:
return attrs
总结:如果有问题就主动抛异常
如果没有问题还把数据返回出去
标签:return,self,request,drf,组件,序列化,data,view
From: https://www.cnblogs.com/moongodnnn/p/17084016.html