rest framework介绍 (CBV(class base views))

在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:

增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
删:判断要删除的数据是否存在 -> 执行数据库删除
改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
查:查询数据库 -> 将数据序列化并返回

解析url中的 as_view()

url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"),  

继承

APIView继承自View,APIView中有as_view方法,方法中会执行下面这段代码

执行了父类的as_view方法,得到view函数,执行dispatch方法(一切的开始)

序列化

序列化用于对用户请求数据进行验证和数据进行序列化

第一种表示方法——Serializers

from rest_framework import serializers
from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
price = serializers.IntegerField()
pub_date = serializers.DateField() class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,将数据库查询字段序列化为字典
obj = models.Book.objects.all()
ser = BookSerializer(obj, many=True)
# 如果不是queryset,就不用加many=True
# obj = models.Book.objects.all().first()
# ser = BookSerializer(obj, many=False)
return Response(ser.data) def post(self, request, *args, **kwargs):
# 验证,对请求发来的数据进行验证
ser = BookSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('Post请求')

第二种表示方法——ModelSerializers:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from app01 import models class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__" # 全部
# fields = ['title', 'price'] 只查两项
# depth = 2 # 查询深度
# exclude = ('price',) 除了price不查询 class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,将数据库查询字段序列化为字典
obj = models.Book.objects.all()
ser = BookSerializer(obj, many=True)
# 如果不是queryset,就不用加many=True
# obj = models.Book.objects.all().first()
# ser = BookSerializer(obj, many=False)
return Response(ser.data) def post(self, request, *args, **kwargs):
# 验证,对请求发来的数据进行验证
ser = BookSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
ser.save() # create 方法
return Response(ser.data)
else:
print(ser.errors)
return Response('Post请求')

特殊取值(取user_type对应的中文)

class UserInfo(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices)
class UserInfoSerializer(serializers.Serializer):
xxxxx = serializers.CharField(source="user_type") # row.user_type source将xxxx对应为user_type
oooo = serializers.CharField(source="get_user_type_display") # row.get_user_type_display() 数据:[{"xxxx":1,"oooo":"普通用户"}]

多表查询

一对多查询通过source实现

from django.db import models

class UserGroup(models.Model):
title = models.CharField(max_length=32) class UserInfo(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64) group = models.ForeignKey("UserGroup")
roles = models.ManyToManyField("Role") class UserToken(models.Model):
user = models.OneToOneField(to='UserInfo')
token = models.CharField(max_length=64) class Role(models.Model):
title = models.CharField(max_length=32)

models

from rest_framework.views import APIView
from rest_framework import serializers
from . import models
from rest_framework.response import Response class UserInfoSerializers(serializers.Serializer):
user_type = serializers.IntegerField()
user_type_choices = serializers.CharField(source="get_user_type_display")
group = serializers.CharField(source="group.title")   

 多对多通过自定义实现

class UserInfoSerializers(serializers.Serializer):
user_type = serializers.IntegerField()
user_type_choices = serializers.CharField(source="get_user_type_display")
group = serializers.CharField(source="group.title")
rls = serializers.SerializerMethodField() def get_rls(self, obj): # get_rls和上边rls要对应
ret = []
for item in obj.roles.all():
print(item)
ret.append({"id": item.id, "title": item.title})
return ret

View

 在视图中生成url

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^userinfo/$', views.UserInfoView.as_view(), ),
url(r'^group/(?P<pk>\d+)$', views.GroupView.as_view(), name='gp'),

urls

from rest_framework.views import APIView
from rest_framework import serializers
from . import models
from rest_framework.response import Response
from django.http import HttpResponse
import json class RoleSerializers(serializers.ModelSerializer):
class Meta:
model = models.Role
fields = "__all__" class UserInfoSerializers(serializers.Serializer):
group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk')
user_type = serializers.IntegerField()
user_type_choices = serializers.CharField(source="get_user_type_display")
# group = serializers.CharField(source="group.id")
rls = serializers.SerializerMethodField() def get_rls(self, obj):
ret = []
for item in obj.roles.all():
print(item)
ret.append({"id": item.id, "title": item.title})
return ret class UserInfoView(APIView):
def get(self, request):
obj = models.UserInfo.objects.all()
ser = UserInfoSerializers(obj, many=True, context={'request': request})
return Response(ser.data) class GroupSerializers(serializers.Serializer):
class Meta:
model = models.UserGroup
fields = '__all__' class GroupView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
obj = models.UserGroup.objects.filter(pk=pk).first()
ser = GroupSerializers(obj, many=False)
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)

View

group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk')
lookup_url_kwarg='pk'是和url中的(?P<pk>\d+)$'的pk对应,lookup_field='group_id'是取group的id值
ser = UserInfoSerializers(obj, many=True, context={'request': request}) context是必须添加的

序列化验证钩子(validate+校验字段名)

class RoleSerializers(serializers.ModelSerializer):
class Meta:
model = models.Role
fields = "__all__" # 局部钩子
def validate_title(self, attrs):
if attrs.startswith(""):
raise ValidationError("不能以666开头")
return attrs # 全局钩子
def validate(self, attrs): return attrs

View

视图

a. GenericAPIView(没什么用)

from rest_framework import serializers
from . import models
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response class RoleSerializers(serializers.ModelSerializer):
class Meta:
model = models.Role
fields = '__all__' class RoleView(GenericAPIView):
queryset = models.Role.objects.all()
serializer_class = RoleSerializers def get(self, request, *args, **kwargs):
# 获取数据
obj = self.get_queryset()
# 序列化
ser = self.get_serializer(obj, many=True)
return Response(ser.data)

View

b. GenericViewSet

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^role/$', views.RoleView.as_view({'get': 'list'}), ), # 和view里边的list方法做对应关系

urls

class RoleSerializers(serializers.ModelSerializer):
class Meta:
model = models.Role
fields = '__all__' class RoleView(GenericViewSet):
queryset = models.Role.objects.all()
serializer_class = RoleSerializers def list(self, request, *args, **kwargs):
# 获取数据
obj = self.get_queryset()
# 序列化
ser = self.get_serializer(obj, many=True)
return Response(ser.data)

View

c. ModelViewSet

class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^role/$', views.RoleView.as_view({'get': 'list', 'post': 'create'}), ),
url(r'^role/(?P<pk>)\d+/$', views.RoleView.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update', 'patch': 'partial_update'}), ), ]

urls

class RoleView(ModelViewSet):
queryset = models.Role.objects.all()
serializer_class = RoleSerializers

View

a. 增删改查 ModelViewSet

b. 增删 CreateModelMixin,DestroyModelMixin GenericViewSet

c. 复杂逻辑 GenericViewSet 或 APIView

路由

会自动生成增删改查等url

from django.conf.urls import url, include
from django.contrib import admin
from app01 import views
from rest_framework import routers router = routers.DefaultRouter()
router.register(r'role', views.RoleView) urlpatterns = [
url(r'^', include(router.urls)),
]

urls

认证

a.用户url传入的token认证

from rest_framework.authentication import BasicAuthentication
from rest_framework import exceptions class MyAuthentication(BasicAuthentication):
def authenticate(self, request):
token = request.GET.get('token')
token_obj = models.UserToken.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed('Token认证失败')
else:
return token_obj.username, token_obj.token # 验证通过返回元祖,第一个参数和request.user是对应的,所以最好是用户名 class RoleView(ModelViewSet):
authentication_classes = [MyAuthentication, ]
queryset = models.Role.objects.all()
serializer_class = RoleSerializers

View

b.用户登录添加token

class RoleView(ModelViewSet):
authentication_classes = []
queryset = models.Role.objects.all()
serializer_class = RoleSerializers def post(self, request, *args, **kwargs):
res = {'state_code': 1000, 'msg': None}
try:
name = request._request.POST.get('username')
pwd = request._request.POST.get('password')
user = models.UserInfo.objects.filter(username=name, password=pwd).first()
if not user:
res["state_code"] = 1001 # 错误状态码
res["msg"] = "用户名或者密码错误"
else:
# 为用户创建token
token = md5(name)
# 存在就更新,否则就创建
models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
res['token'] = token
except Exception as e:
res['state_code'] = 1002
res['msg'] = '请求异常'
return Response(res)

View

BasicAuthentication、SessionAuthentication、TokenAuthentication、JSONWebTokenAuthentication 都属于认证都继承BaseAuthentication,方法类似

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication', # 基本认证
'rest_framework.authentication.SessionAuthentication', # session认证
)
}

Setting

权限

class MyPermission(BasePermission):
def has_permission(self, request, view):
message = '只有SVIP可以访问'
if request.user != 3:
return False
return True # 局部
permission_classes = [MyPermission, ]

View

频率

from rest_framework.throttling import SimpleRateThrottle

class VisitThrottle(SimpleRateThrottle):
# 配置文件中进行配置
scope = 'Luffy' def get_cache_key(self, request, view):
return self.get_ident(request) class UserThrottle(SimpleRateThrottle):
scope = 'LuffyUser' 局部
throttle_classes = [VisitThrottle, ]

View

REST_FRAMEWORK = {
"DEFAULT_THROTTLE_RATES": {
"Luffy": '3/m',
"LuffyUser": '10/m',
}
}

Setting

版本

a.url的get传参方式

/user?version=v1

REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}

setting

from rest_framework.versioning import QueryParameterVersioning

class TestView(APIView):
versioning_class = QueryParameterVersioning def get(self, request, *args, **kwargs): # 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme) # 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url) return Response('GET请求,响应内容')

b.基于url正则表达式

/v1/user/

REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning'
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}

setting

class TestView(APIView):
# 局部
versioning_class = URLPathVersioning def get(self, request, *args, **kwargs):
# 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme) # 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)

View

urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
]

urls

解析器

用于处理不同请求头数据

REST_FRAMEWORK = {
"DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser']
}

setting

class ParserView(APIView):
# parser_classes = [JSONParser,FormParser,]
"""
JSONParser:表示只能解析content-type:application/json头
FormParser:表示只能解析content-type:application/x-www-form-urlencoded头
""" def post(self,request,*args,**kwargs):
"""
允许用户发送JSON格式数据
a. content-type: application/json
b. {'name':'alex',age:18}
:param request:
:param args:
:param kwargs:
:return:
"""
"""
1. 获取用户请求
2. 获取用户请求体
3. 根据用户请求头 和 parser_classes = [JSONParser,FormParser,] 中支持的请求头进行比较
4. JSONParser对象去请求体
5. request.data
"""
print(request.data) return HttpResponse('ParserView')

View

dispatch

  

rest_framwork组件的更多相关文章

  1. DRF框架之 serializers 序列化组件

    1. 什么是序列化,其实在python中我们就学了序列化工具json工具,就是吧信息存为类字典形式 2. DRF框架自带序列化的工具: serializers 3. DRF框架 serializers ...

  2. DRF 视图组件,路由组件

    视图组件  -- 第一次封装   -- GenericAPIView(APIView):    queryset = None    serializer_class = None    def ge ...

  3. rest-framework框架的基本组件

    快速实例 Quickstart 大致步骤 (1)创建表,数据迁移 (2)创建表序列化类BookSerializer class BookSerializer(serializers.Hyperlink ...

  4. DRF-->2序列化组件的使用和接口设计--get,post,put,delete&优化组件

    !!!!! !!!!! 记住这个图 !!!!! 上篇博客说道DRF序列化组件的get,只是简单的举一个实例,然而在现实生活中我们前后端进行交互的时候更多的用到了Json数据格式,这也就是说前后端交互的 ...

  5. ExtJS 4.2 评分组件

    上一文章是扩展ExtJS自带的Date组件.在这里将创建一个评分组件. 目录 1. 介绍 2. 示例 3. 资源下载 1. 介绍 代码参考的是 Sencha Touch 2上的一个RatingStar ...

  6. react组件的生命周期

    写在前面: 阅读了多遍文章之后,自己总结了一个.一遍加强记忆,和日后回顾. 一.实例化(初始化) var Button = React.createClass({ getInitialState: f ...

  7. react-router 组件式配置与对象式配置小区别

    1. react-router 对象式配置 和 组件式配置    组件式配置(Redirect) ----对应---- 对象式配置(onEnter钩子) IndexRedirect -----对应-- ...

  8. Angular2入门系列教程3-多个组件,主从关系

    上一篇 Angular2项目初体验-编写自己的第一个组件 好了,前面简单介绍了Angular2的基本开发,并且写了一个非常简单的组件,这篇文章我们将要学会编写多个组件并且有主从关系 现在,假设我们要做 ...

  9. Angular2入门系列教程2-项目初体验-编写自己的第一个组件

    上一篇 使用Angular-cli搭建Angular2开发环境 Angular2采用组件的编写模式,或者说,Angular2必须使用组件编写,没有组件,你甚至不能将Angular2项目启动起来 紧接着 ...

随机推荐

  1. OpenStack概念

    OpenStack is a global collaboration ofdevelopers and cloud computing technologists producing the ubi ...

  2. SQLSERVER 2012的多维数据库浏览 ,不能多维的显示

    网上搜索后发现,原来ssms2012不支持这种方式,要使用Excel的方式 参考地址:http://www.flybi.net/question/12567

  3. C#开发usb通知之bulk传输

    usb通信分为4种传输方式,下位机通信协议用的是块传输,也就是bulk传输,C#下实现的usb通信使用的是开源的LibUsbDotNet,主要的就是需要在C#中添加LibUsbDotNet.dll引用 ...

  4. spring笔记2-注解

    一.属性与成员变量的区别: 属性:对外暴露的,getxxx/setxxx称为属性; 成员变量:private String name称为成员变量或字段 二.applicationContext.xml ...

  5. vue-router配置

    首先在App.vue中 1.使用router-link组件来导航,通过‘to'属性指定链接,<router-link> 默认会被渲染成一个 `<a>` 标签 <route ...

  6. 《ArcGIS Runtime SDK for Android开发笔记》——(8)、关于ArcGIS Android开发的未来(“Quartz”版Beta)

    1.前言 今天再一次在官网看到了ArcGIS Runtime SDK for Android下一个版本“Quartz”版的更新资料,它将是一个非常重要的更新,包括API接口的重构和开发思路的调整.具体 ...

  7. SaaS “可配置”和“多租户”架构的几种技术实现方式

    1.数据存储方式的选择 多租户(Multi-Tenant ),即多个租户共用一个实例,租户的数据既有隔离又有共享,说到底是要解决数据存储的问题. 常用的数据存储方式有三种. 方案一:独立数据库   一 ...

  8. EasyUI手风琴 Tab卡使用

    --案例项目代码,初始化手风琴,定义打开Tab的方法. $(result).each(function () { //m_pi_jscode,pi_jscode if (m_pi_id != this ...

  9. Redis 基础概念和命令

    Redis 是什么 Redis是一种基于键值对(key-value)的NoSQL数据库. 为什么使用Redis 速度快 Redis的时间颗粒度一般是微秒,慢查询的默认值是10 000微秒,即10毫秒. ...

  10. 洛谷 P2251 质量检测

    题目背景 无 题目描述 为了检测生产流水线上总共N件产品的质量,我们首先给每一件产品打一个分数A表示其品质,然后统计前M件产品中质量最差的产品的分值Q[m] = min{A1, A2, ... Am} ...