一、APIView基本使用
首先Drf是一个Django第三方的App 它只适用于Django 如果使用到别的框架是使用不了的
安装Drf之后就可以导入一个视图累APIView 所以要使用Drf写视图类 都要继承APIView以及其子类
在安装完Drf(DjangoRestFrameWork)它会默认把系统的Django版本更新到最新 这个时候运行会报错 只要把Drf或者Django版本降低即可
首先展示使用View展示接口
path('movies/', MovieView.as_view())
class Movie(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
director = models.CharField(max_length=32)
class MovieView(View):
def get(self, request):
movie_list = Movie.objects.all()
res_list = []
for movie in movie_list:
res_list.append({'name': movie.name, 'price': movie.price, 'director': movie.director})
return JsonResponse(res_list, safe=False, json_dumps_params={'ensure_ascii': False})
'''
JsonResponse只能序列化字典以及列表 safe如果是True会抛出异常
json_dumps_params={'ensure_ascii': False}把数据转换成中文
movie_list是一个queryset对象不能直接序列化 只能通过for循环一个一个拼成列表套字典形式
'''
访问结果:[{"name": "今天你做了嘛?", "price": "999", "director": "Mr.Mei"},
{"name": "我也想做!", "price": "666", "director": "Mr.Jin"}]
使用APIView+Response展示接口
from rest_framework.views import APIView
from rest_framework.response import Response
# Drf的视图类比较规范 导入都有单独的模块
class MovieView(APIView):
def get(self, request):
# print(type(self.request)) # 新的request
# print(type(request))
print(request._request) # <WSGIRequest: GET '/movies/'>
print(type(request._request)) # django.core.handlers.wsgi.WSGIRequest
# print(request.method) # get
# print(request.path) # /movies/
# print(request.GET) # 原来的get请求提交的参数
# print(request.POST) # 原来post请求提交的参数
movie_list = Movie.objects.all()
# book_list是queryset对象不能直接序列化,只能通过for循环一个个拼成列表套字典的形式
res_list = []
for movie in movie_list:
res_list.append({'name': movie.name, 'price': movie.price, 'director': movie.director})
return Response(res_list)
'''
注意一定到在Settings里面注册Drf这个app 如果不注册用浏览器访问会报错
如果注册了使用浏览器浏览就会看到一个被美化的界面 不仅仅是Json格式的数据
'''
二、APIView源码分析
首先入口APIView
class MovieView(APIView):
# 进入源码查看as_view 把多余的源码删除看主要的 首先看自身在看继承的
@classmethod
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs)
return csrf_exempt(view)
# 第一层就做了一件事Super调用了父类的as_view把自己的参数传递的了进去 然后把所有的请求csrf检验去除了
所以请求来了路由匹配成功会执行View类里面的as_view类方法内的View闭包函数实际上还是view的as_view没有csrf验证
# 再点进继承的view类里面查看 真正执行的是self.dispatch
def view(request, *args, **kwargs):
return self.dispatch(request, *args, **kwargs)
# 再点进来查看dispatch的流程
def dispatch(self, request, *args, **kwargs):
# 参数的request是Django原生的request
# 下面的request变成了Drf提供的Request类的对象不是原生的了
request = self.initialize_request(request, *args, **kwargs)
self.request = request
# self是视图类的对象 视图类对 request=request 新的request
self.headers = self.default_response_headers
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类源码分析
#1 视图类中使用的request对象 已经变成了drf提供的Request类的对象了
-原生djagno 的request是这个类的对象:django.core.handlers.wsgi.WSGIRequest
-drf的request是这个类的对象:rest_framework.request.Request
#2 request已经不是原来的request了 还能像原来的request一样使用吗?
-用起来,像之前一样
print(request.method) # get
print(request.path) # /movies/
print(request.GET) # 原来的get请求提交的参数
print(request.POST) # 原来post请求提交的参数
#3 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
-data 是个方法,被property装饰了,变成了数据属性用
-以后body体中提交的数据,都从这里取(request.POST)
-urlencoded,form-data:提交的数据在request.POST中
-json格式提交的数据,在requets.POST中没有 它在request.body中
-现在无论那种格式,都从request.data中取
-query_params:get请求提交的参数 等同于request._request.GET 或 request.GET
-其他:取文件也是从request.FILES中取 跟之前一样
验证 原生requets.POST 只有urlencoded和form-data格式提交的数据 json格式提交的数据在body中
拿出来自己处理 但是drf的request中有个data data中可以取到任意编码提交的数据
request.data 有时候是(urlencoded,form-data)QueryDict 有时候(json)是字典
# 4 什么是魔法方法?
1 在类中只要以__开头 __结尾的都称之为魔法方法
2 这种方法不需要手动调用,某种情况会自动触发
3 讲过的: __init__,__str__,__call__,......
四、序列化组件介绍
咱在写电影接口的时候涉及到一个问题 要把Queryset单个Movie对象转换成Json格式字符串给前端这个过程就叫做序列化
要是我们现在只要电影名以及导演呢?(就得去删除或者添加)于是Drf就给我们提供了一种可以快速实现序列化的类就跟Forms很像了
基于APIView+Response+序列化类写接口
创建一个文件 serializer.py
from rest_framework.serializers import Serializer
from rest_framework import serializers
class MovieSerializers(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
director = serializers.CharField()
# 新增数据直接再写一个字段 删除直接删除即可 字段类里面可以写很多字段属性
views
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializer import MovieSerializers
class MovieView(APIView):
def get(self, request):
movie_list = Movie.objects.all()
# instance表示要序列化的数据,many=True表示序列化多条(instance是qs对象,一定要传many=True)
ser = MovieSerializers(instance=movie_list, many=True)
return Response(ser.data)
'''这个时候我们如果需要添加一条数据在类里面添加字段即可 如果想不要删除掉即可 这就非常的方便'''
五、序列化组件基本使用
urls.py
urlpatterns = [
path('admin/', admin.site.urls), # 自带管理员
path('movies/', MovieView.as_view()), # 获取多条数据
path('movies/<int:pk>/', MovieDetailView.as_view()), # 获取单条数据
]
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializer import MovieSerializers
class MovieView(APIView): # 获取多条数据
def get(self, request):
movie_list = Movie.objects.all()
# instance表示要序列化的数据,many=True表示序列化多条(instance是qs对象,一定要传many=True)
ser = MovieSerializers(instance=movie_list, many=True)
# instance产生一个对象赋值接收 many通过字面都知道什么意思就是获取更多many=True
return Response(ser.data)
class MovieDetailView(APIView): # 获取单条数据
def get(self, request, pk):
movie = Movie.objects.filter(pk=pk).first()
ser = MovieSerializers(instance=movie)
return Response(ser.data)
'''
获取单条与获取多条的方式都是Get 但是如果多条与单条一起使用混合度比较高 所以单独重写一个获取单条的类
我们发送Get请求单条数据都会跟上ID号所以基本格式是这样 http://127.0.0.1:8000/movies/1/ 所以要在类中添加到ID才能获取到哪一条数据
'''
六、反序列化基本使用
序列化就是查询多个以及查询单个 但是反序列化就是新增和修改了 删除直接删除即可不涉及到序列化
新增
class MovieView(APIView): # 获取多条数据
def get(self, request):
movie_list = Movie.objects.all()
# instance表示要序列化的数据,many=True表示序列化多条(instance是qs对象,一定要传many=True)
ser = MovieSerializers(instance=movie_list, many=True)
return Response(ser.data)
def post(self, request):
ser = MovieSerializers(data=request.data) # 从前端传递数据从request.data中取出来
if ser.is_valid(): # is_valid表示校验前端传入的数据 但是我们没有写入校验规则
ser.save()
''' 这个时候发送post请求会发生报错 NotImplementedError: `create()` must be implemented.
这个时候点击我们点击save查看源码是调用了Save会触发BaseSerializer的方法
判断了 如果instance有值执行update,没有值执行create 看到create没有写 所以我们得重写Create'''
return Response(ser.data)
else:
return Response(ser.errors)
'''重写create方法'''
class MovieSerializers(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
director = serializers.CharField()
def create(self, validated_data):
res = Movie.objects.create(**validated_data)
return res
修改
class MovieDetailView(APIView): # 获取单条数据
def get(self, request, pk):
movie = Movie.objects.filter(pk=pk).first()
ser = MovieSerializers(instance=movie)
return Response(ser.data)
def put(self, request, pk):
movie = Movie.objects.filter(pk=pk).first()
ser = MovieSerializers(instance=movie, data=request.data)
if ser.is_valid():
ser.save() # 跟上方的新增一样 我们需要去重写update方法
return Response(ser.data)
else:
return Response(ser.errors)
# 重写update方法
def update(self, instance, validated_data):
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.director = validated_data.get('director')
instance.save()
return instance
# instance要修改的对象 validated_data校验过后的数据
删除
def delete(self, request, pk):
Movie.objects.filter(pk=pk).delete()
return Response()
技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请
点点赞收藏+关注
谢谢支持 !!!