博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

drf快速使用

# 原生django,不使用任何其他模块,也可以写出符合resful规范的接口---》写起来麻烦一些
# 查询所有图书
地址:127.0.0.1:8080/books
 路由:path('/books',views.books)
 视图函数中:通过orm查出所有图书(qs)--->序列化(for循环自己拼成列表套字典[{name:西游记,price:99},{name:红楼梦,price:99}])---->JsonResponse返回给前端
# drf是django的一个app--》帮助咱们快速在django上写符合restful规范的接口
# 安装:
pip3 install djangorestframework
   
# 针对于一个表,需要写那些接口---》5个--》以后看到的所有接口都是这5个的变形
-查询所有---》get->http://127.0.0.1:8000/books/
 -查询一个---》get->http://127.0.0.1:8000/books/1/
 -新增一个---》post->http://127.0.0.1:8000/books/ body中带数据
 -修改-----》put,patch--->实际编码中,基本都用put
http://127.0.0.1:8000/books/1/ body体中传入修改的数据
 -删除一个---》delete-->http://127.0.0.1:8000/books/1/
       
1.创建序列化器类(应用目录中新建serializers.py用于保存该应用的序列化器)
# 创建序列化器类,在视图中调用
from .models import Book
from rest_framework import serializers

class BookSerializer(serializers.ModelSerializer):
   class Meta:
       model=Book
       fields='__all__'
2.编写视图
from rest_framework.viewsets import ModelViewSet
from .models import Book  # 相对导入
from .serializers import BookSerializer
class BookView(ModelViewSet):
   queryset=Book.objects.all()  # 指明该视图集在查询数据时使用的查询集
   serializer_class = BookSerializer  # serializer_class 指明该视图在进行序列化或反序列化时使用的序列化器
3.定义路由
from rest_framework.routers import SimpleRouter
from app01 import views

router=SimpleRouter()
router.register('books',views.BookView,'books')
urlpatterns = [
   path('admin/', admin.site.urls),
]
urlpatterns+=router.urls
4.运行测试
 

1 CBV源码分析和APIView源码分析

 

1.1 cbv执行流程

    from django.views import View
   path('test/',views.TestView.as_view()),
   # path('test/',View类的as_view内部有个view闭包函数内存地址),
   '''
  1 path的第二个参数是:View类的as_view内部有个view闭包函数内存地址
  2 一旦有请求来了,匹配test路径成功
  3 执行第二个参数view函数内存地址(requset)
  4 本质执行了self.dispatch(request)
  5 通过反射去获得方法(如果是get请求,就是get方法)
    if request.method.lower() in self.http_method_names:
      handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
  6 执行get方法,传入参数
  handler(request, *args, **kwargs)
  '''

1.2 APIView的执行流程

    from rest_framework.views import APIView
   # path('test/',APIView类的as_view内部是用了View的as_view内的view闭包函数),
   '''
  1 path的第二个参数是:APIView类的as_view内部是用了View的as_view内的view闭包函数
  2 一旦有请求来了,匹配test路径成功
  3 执行第二个参数view函数内存地址(requset),还是执行View的as_view内的view闭包函数,但是加了个csrf_exempt装饰器
  4 所以,继承了APIView的所有接口,都没有csrf的校验了 (*****************)
  5 执行self.dispatch(request)----》APIView类的
      def dispatch(self, request, *args, **kwargs):
          # 以后所有的request对象,都是****新的request对象***,它是drf的Request类的对象
          request = self.initialize_request(request, *args, **kwargs)
          self.request = request
          try:
              #整个drf的执行流程内的权限,频率,认证
              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

  '''
   
### request = self.initialize_request(request, *args, **kwargs)
##返回的request对象是drf   Request类的request对象
from rest_framework.request import Request
def initialize_request(self, request, *args, **kwargs):
   return Request(
       request,
       parsers=self.get_parsers(),
       authenticators=self.get_authenticators(),
       negotiator=self.get_content_negotiator(),
       parser_context=parser_context
  )
### *******以后,在视图类中使用的request对象已经不是原来的request对象了,现在都是drf的request对象了



#####总结
-0 所有的csrf都不校验了
-1 request对象变成了新的request对象,drf的request对象
   -2 执行了权限,频率,认证
   -3 捕获了全局异常(统一处理异常)
   -4 处理了response对象,如果浏览器访问是一个样,postman访问又一个样
   -5 以后,在视图类中使用的request对象已经不是原来的request对象了,现在都是drf的request对象了
 

 

2 Request对象分析

1 django 原生的Request:django.core.handlers.wsgi.WSGIRequest
2 drf的Request:rest_framework.request.Request

3 drf的request对象内有原生的request
request._request:原生的Request
4 在视图类中使用
request.method  拿到的就是请求方式,
   正常拿,应该request._request.method
5 如何实现这种操作?
-对象.属性会触发 类的__getattr__方法
   
   
6 drf的Request类重写了__getattr__
   def __getattr__(self, attr):
       try:
           # 去原生的request反射属性
           return getattr(self._request, attr)
       except AttributeError:
           return self.__getattribute__(attr)
       
       
7 虽然视图类中request对象变成了drf的request,但是用起来,跟原来的一样,只不过它多了一些属性
-request.data  #post请求提交的数据,不论什么格式,都在它中
   -requst.query_params# get请求提交的数据(查询参数)
   
   
8 总结:
-drf的request对象用起来跟原来一样(重写了__getattr__)
   -request.data  #post请求提交的数据,不论什么格式,都在它中
   -requst.query_params# get请求提交的数据(查询参数)

 

3 序列化器的作用

1 序列化:把python中的对象转成json格式字符串
2 反序列化:把json格式字符串转成python中的对象


3 注意:drf的序列化组件(序列化器)
把对象(Book,queryset对象)转成字典
   因为有字典,直接丢到Response中就可以了
   
   

 

4 序列化器的使用

'''
序列化器的使用分两个阶段:

在客户端请求时,使用序列化器可以完成对数据的反序列化。
在服务器响应时,使用序列化器可以完成对数据的序列化。
'''
1 写一个序列化的类,继承Serializer
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
   # 在这里写要序列化的字段
   # 序列化字段类(有很多,常用的就几个,等同于models中的字段类)
   # 字段类,有很多字段参数()
   name = serializers.CharField()
   price = serializers.IntegerField()
   # publish = serializers.CharField()
2 在类中写要序列化的字段
name = serializers.CharField()
   price = serializers.IntegerField()
3 在视图类中使用(实例化)
book_list = models.Book.objects.all()             book_ser=BookSerializer(instance=book_list,many=True)  # many=True序列化多条
   '''
  Serializer(instance=None, data=empty, **kwarg)
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
serializer = AccountSerializer(account, context={'request': request})

通过context参数附加的数据,可以通过Serializer对象的context属性获取。

      使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
      序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
      序列化器的字段声明类似于我们前面使用过的表单系统。
      开发restful api时,序列化器会帮我们把模型数据转换成字典.
      drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.
  '''
4 得到序列化后的数据,返回
return Response(book_ser.data)
   
5 字段参数,source,指定要序列化表中的哪个字段

 

4.2 source

1 指定要序列化的字段(数据表中字段)
publish = serializers.CharField(source='publish.city')  # 跨表拿

2 用的最多:只有一个字段(也可以跨表)

 

4.2 SerializerMethodField

1 用的最多,跨表查(要么是列表,要么是字典)
publish=serializers.SerializerMethodField()
def get_publish(self,obj):
       print(obj)
       # return {'name':'sss','city':'sss'}
       return {'name':obj.publish.name,'city':obj.publish.city}

4.3 在模型表中写方法

# 表模型中写的
def publish_name(self):
  return {'name':self.publish.name,'city':self.publish.city}

@property
def author_list(self):
  return [{'name':author.name,'age':author.age,'id':author.nid} for author in self.authors.all()]

#序列化类中
# publish = serializers.CharField(source='publish_name')
publish_name = serializers.DictField()
author_list=serializers.ListField()