Django-Rest-Framework

一、什么是restful?

REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”、
REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)

二、restful API设计(规范)

一、API与用户的通信协议,总是使用HTTPS协议
二、域名
    https:api.zhangjianping.com     尽量将API部署在专用的域名(不存在跨域问题)
    https:zhangjianping.org/api      简单的API
三、版本
    URL:   https:api.zhangjianping.com/v1
    请求头           跨域时,引发发送多次请求
四、路径,网络上的东西都是资源,均使用名词去表示
五、method
    GET:从服务器取出资源(一项或者是多项)
    POST:在服务器新建一个资源
    PUT:在服务器更新资源(客户端提供改变后的完整资源)
    PATCH:在服务器更新资源(客户端提供改变的属性)
    DELETE:从服务器删除资源
六、过滤
    通过在url上传参的形式传递搜索条件
七、状态码
八、错误处理
九、返回结果
十、Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
状态码附录

三、基于Django实现

路由系统:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/$',views.User.as_view()),
]

CBV视图:

from django.http import JsonResponse
from django.views import View
class User(View):
    def get(self,request,*args,**kwargs):
        result = {
            "status":True,
            "data":"response data"
        }
        return JsonResponse(result,status=200)
    def post(self,request,*args,**kwargs):
        result = {
            "status":True,
            "data":"response data"
        }
        return JsonResponse(result,status=200)

四、基于Django-Rest-Framework框架实现

1、基本流程

路由系统:

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^test/$',views.TestView.as_view())
]

CBV视图:

from rest_framework.views import APIView
from rest_framework.response import Response

class TestView(APIView):
    def dispath(self,request,*args,**kwargs):
    """请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发不同的函数来处理"""
return super().dispatch(request,*args,**kwargs) def get(self,request,*args,**kwargs): return Response("GET请求,响应内容") def post(self,request,*args,**kwargs): return Response("POST请求,响应内容") def put(self,request,*args,**kwargs): return Response("PUT请求,响应内容")

以上这段代码就是rest framework框架的基本流程,重要的功能都是在APIView中的dispatch中触发的

当你运行上段代码会报错:

你使用的是restframework,但是模板用的却是Django的,所以报错在所难免,解决的办法就是在配置文件中注册

 2、认证和授权

路由系统

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^test/$',views.TestView.as_view())
]

CBV视图:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions

token_list = [
    "zhangjianping",           #可以授权的数据
]

class TestAuthentication(BaseAuthentication):
    def authenticate(self, request):
        '''
        用户认证,认证成功后返回元组
        :param request:
        :return:
        '''
        val = request.query_params.get("token")    #get请求从网址栏获取到的数据
        if val not in token_list:                  #判断当前url是否可以授权访问
            raise exceptions.AuthenticationFailed("用户认证失败")
        return ("登录用户,","用户token")
    def authenticate_header(self, request):
        pass


class TestView(APIView):
    '''
    调用这个函数的时候,会自动触发authentication_classes的运行,所以会先执行上边的类
    '''
    authentication_classes = [TestAuthentication,]
    permission_classes = []


    def get(self,request,*args,**kwargs):
        print("====request.user====",request.user)         #当前登录的用户
        print("====request.auth====",request.auth)         #获取到的用户token
        return Response("GET请求,响应内容")

    def post(self,request,*args,**kwargs):
        return Response("POST请求,响应内容")

    def put(self,request,*args,**kwargs):
        return Response("PUT请求,响应内容")

3、用户登录

路由系统:

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
  url(r'^auth/$',views.AuthView.as_view()),
]

model表操作:

from django.db import models

class UserInfo(models.Model):
    username = models.CharField(max_length=16)
    password = models.CharField(max_length=16)
    token = models.CharField(max_length=64,null=True)

CBV视图:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions
import time,hashlib
from app01 import models

class AuthView(APIView):
    authentication_classes = []
    def get(self,request):
        ret = {"code":1000,"msg":None}
        user = request.query_params.get("user")
        pwd = request.query_params.get("pwd")
        obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
        if not obj:    #如果没有获取到用户信息执行
            ret["code"] = 1001
            ret["msg"] = "用户名或密码错误"
            return Response(ret)
        ctime = time.time()   #得到一个时间戳
        key = "%s|%s"%(user,ctime)    #类似于加密盐
        m = hashlib.md5()
        m.update(key.encode("utf-8"))
        token = m.hexdigest()        #token经过MD5加密处理
        obj.token = token            #数据库的空字符串,颁发授权信息
        ret["token"] = token         #写入数据表
        return Response(ret)

 4、限制访问频率

 路由系统

from django.conf.urls import url
from django.contrib import admin
from app01 import views
from app02 import views as app02_view
from app03 import views as app03_view
urlpatterns = [
rl(r'^salary/', app02_view.SalaryView.as_view()),
    url(r'^limit/', app03_view.LimitView.as_view()),
]
#配置文件
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ # "app02.utils.MyAuthentication", ], 'DEFAULT_PERMISSION_CLASSES':[ ], 'DEFAULT_THROTTLE_RATES':{ 'wdp':'2/minute' #每分钟两次 } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': 'cache', 数据默认报错在缓存 } }
#生写,自己实现            -----CBV视图
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle

from rest_framework import exceptions

RECORD = {

}
class MyThrottle(BaseThrottle):
    def allow_request(self,request,view):
        """
        # 返回False,限制
        # 返回True,通行
        :param request: 
        :param view: 
        :return: 
        """
        """
         a. 对匿名用户进行限制:每个用户1分钟允许访问10次
            - 获取用户IP request 1.1.1.1
        """
        import time
        ctime = time.time()          #获取当前时间
        ip = self.get_ident(request)        #获取IP
        if ip not in RECORD:         #IP没有在新建的那个字典
            RECORD[ip] = [ctime,]    #将当前的IP作为key,时间作为value列表
        else:
            # [4507862389234,3507862389234,2507862389234,1507862389234,]
            time_list = RECORD[ip]         #如果在的话获取IP时间列表
            while True:
                val = time_list[-1]        #取出最后一个值
                if (ctime-60) > val:       #如果当前的时间-60秒>取出的最后一个值
                    time_list.pop()        #就将这个值取出来
                else:
                    break
            if len(time_list) > 10:    #一分钟访问次数超过10次,return False
                return False
            time_list.insert(0,ctime)    #将当前时间插入到第一个位置
        return True
    def wait(self,request):
        """
        :return: 返回需要等待的时间
        """
        import time
        ctime = time.time()
        first_in_time = RECORD[self.get_ident(request)][-1]
        wt = 60 - (ctime - first_in_time)      #等待的时间
        return wt

class LimitView(APIView):
    authentication_classes = []
    permission_classes = []
    throttle_classes=[MyThrottle,]
    def get(self,request,*args,**kwargs):
        # self.dispatch
        return Response('控制访问频率示例')

    def throttled(self, request, wait):
        """
        If request is throttled, determine what kind of exception to raise.
        """

        class MyThrottled(exceptions.Throttled):
            default_detail = '请求被限制.'
            extra_detail_singular = 'Expected available in {wait} second.'
            extra_detail_plural = '还需要再等待{wait}'

        raise MyThrottled(wait)

 CBV路由系统

class MySimpleRateThrottle(SimpleRateThrottle):
    scope = "wdp"

    def get_cache_key(self, request, view):
        return self.get_ident(request)
class LimitView(APIView):
    authentication_classes = []
    permission_classes = []
    throttle_classes=[MySimpleRateThrottle,]
    def get(self,request,*args,**kwargs):
        # self.dispatch
        return Response('控制访问频率示例')

    def throttled(self, request, wait):
        """
        If request is throttled, determine what kind of exception to raise.
        """

        class MyThrottled(exceptions.Throttled):
            default_detail = '请求被限制.'
            extra_detail_singular = 'Expected available in {wait} second.'
            extra_detail_plural = '还需要再等待{wait}'

        raise MyThrottled(wait)

认证、权限+访问控制的实现

from django.conf.urls import url
from django.contrib import admin
from app04 import views as app04_view

urlpatterns = [
    url(r'^index/', app04_view.IndexView.as_view()),
    url(r'^manage/', app04_view.ManageView.as_view()),
]

setting配置

REST_FRAMEWORK = {
    'UNAUTHENTICATED_USER': None,
    'UNAUTHENTICATED_TOKEN': None,
    "DEFAULT_AUTHENTICATION_CLASSES": [    #认证控制
        # "app02.utils.MyAuthentication",
    ],
    'DEFAULT_PERMISSION_CLASSES':[     #权限控制

    ],
    'DEFAULT_THROTTLE_RATES':{
        'wdp_anon':'5/minute',       #匿名用户配置
        'wdp_user':'10/minute',      #正常用户配置

    }
}

CACHES = {                        #缓存配置
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': 'cache',
    }
}

CBV视图

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
from rest_framework.authentication import BaseAuthentication
from app02 import models

class MyAuthentication(BaseAuthentication):
    """
    用户认证类,获取url传过来的数据
    """
    def authenticate(self, request):
        token = request.query_params.get('token')
        obj = models.UserInfo.objects.filter(token=token).first()
        if obj:
            return (obj.username,obj)
        return None

    def authenticate_header(self, request):
        pass

class MyPermission(object):
    message = "无权访问"
    def has_permission(self,request,view):
        if request.user:
            return True
        return False

class AdminPermission(object):
    message = "无权访问"
    def has_permission(self,request,view):
        if request.user == 'alex':
            return True
        return False


class AnonThrottle(SimpleRateThrottle):
    """
    针对匿名用户的配置
    """
    scope = "wdp_anon"      #配置文件中的值
 
    def get_cache_key(self, request, view):
        # 返回None,表示我不限制
        # 登录用户我不管
        if request.user:          #正常登陆的用户不做限制
            return None
        # 匿名用户                #匿名用户做限制
        return self.get_ident(request)

class UserThrottle(SimpleRateThrottle):
    """
    针对已经登陆的用户所做的配置
    """
    scope = "wdp_user"     #配置文件获取

    def get_cache_key(self, request, view):
        # 登录用户
        if request.user:
            return request.user
        # 匿名用户我不管
        return None


# 无需登录就可以访问
class IndexView(APIView):
    authentication_classes = [MyAuthentication,]          #用户认证
    permission_classes = []                               #无需登陆就可以访问的页面不需要权限的控制
    throttle_classes=[AnonThrottle,UserThrottle,]         #限流
    def get(self,request,*args,**kwargs):
        # self.dispatch
        return Response('无需登陆访问首页')
  
  def throttled(self, request, wait):
    """自定义返回的文本信息"""
  class MyThrottled(exceptions.Throttled):
  default_detail = '请求被限制.'
  extra_detail_singular = 'Expected available in {wait} second.'
  extra_detail_plural = '还需要再等待{wait}'
  raise MyThrottled(wait)

# 需登录就可以访问 class ManageView(APIView): authentication_classes = [MyAuthentication,] permission_classes = [MyPermission,] #需要登陆访问的页面做了权限的控制 throttle_classes=[AnonThrottle,UserThrottle,] def get(self,request,*args,**kwargs): # self.dispatch return Response('需要登陆访问首页')

 5、版本限制

URL做版本限制

urlpatterns = [
    url(r'^api/(?P<version>[v1|v2]+)/', include('api.urls')),
            ]
urlpatterns = [
     url(r'^users/', views.UsersView.as_view(),name='u'),
            ]
class UsersView(APIView):
    # 基于url传参
    # versioning_class = QueryParameterVersioning             get视图中直接采用request.version就可以取值
    # 基于URL http://127.0.0.1:8001/api/v2/users/
    # versioning_class = URLPathVersioning
    # 基于子域名 http://v1.luffy.com/users/
    # versioning_class = HostNameVersioning
    #上边的这些配置是基于局部配置,用的更多的是全局的配置,所以只介绍全局配置  

def get(self,request,*args,**kwargs): self.dispatch print(request.version) # QueryParameterVersioning().detemiin_version() print(request.versioning_scheme) # QueryParameterVersioning() # 当前版本一样的URL url = request.versioning_scheme.reverse(viewname='u',request=request) print(url) # 当前版本不一样的URL from django.urls import reverse url = reverse(viewname='u',kwargs={'version':'v2'}) print(url) return Response('...')
REST_FRAMEWORK = {
        'VERSION_PARAM':'version',          #固定的名字
        'DEFAULT_VERSION':'v1',              #默认版本号
        'ALLOWED_VERSIONS':['v1','v2'],       #可以使用的版本号
        'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning"     #版本由url控制
            }

hostname做版本控制

urlpatterns = [
     url(r'^api/', include('api.urls')),
            ]
urlpatterns = [
     url(r'^users/', views.UsersView.as_view(),name='u'),
            ]
class UsersView(APIView):
     def get(self,request,*args,**kwargs):
         self.dispatch
         print(request.version) # QueryParameterVersioning().detemiin_version()
         print(request.versioning_scheme) # QueryParameterVersioning()
REST_FRAMEWORK = {
    'VERSION_PARAM':'version',
    'DEFAULT_VERSION':'v1',
    'ALLOWED_VERSIONS':['v1','v2'],
                'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"     #根据域名做版本控制
            }
根据hostname做版本限制需要配置域名,这里我们直接修改电脑的host文件做测试(Windows系统的 C:\Windows\System32\drivers\etc;mac本或者Linux的在
# vim /etc/hosts) 直接做以下配置: 127.0.0.1 v1.qqq.com 127.0.0.1 v2.qqq.com

6、解析器

请求的数据进行解析:请求体进行解析。表示服务端可以解析的数据格式的种类。
     Content-Type: application/url-encoding.....
     request.body
     request.POST
            
     Content-Type: application/json.....
     request.body
     request.POST
假如客户端发送的数据是:
     Content-Type: application/json
     '{"name":"alex","age":123}'
那么服务端接受的是:
    读取客户端发送的Content-Type的值 application/json
       parser_classes = [JSONParser,]
       media_type_list = ['application/json',]
        
       如果客户端的Content-Type的值和 application/json 匹配:JSONParser处理数据
       如果客户端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser处理数据
单视图:
class UsersView(APIView):
     parser_classes = [JSONParser,]
                
全局配置:
REST_FRAMEWORK = {
    'VERSION_PARAM':'version',
    'DEFAULT_VERSION':'v1',
    'ALLOWED_VERSIONS':['v1','v2'],
    # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
    'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
    'DEFAULT_PARSER_CLASSES':[
              'rest_framework.parsers.JSONParser',            #解析jsonparser
              'rest_framework.parsers.FormParser',            #解析formparser
                    ]
                }

7、序列化操作

#需要导入的包和模块
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BasicAuthentication
from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning,HostNameVersioning
from rest_framework.renderers import BrowsableAPIRenderer,JSONRenderer
from rest_framework.parsers import JSONParser,FormParser
from rest_framework.request import Request
from rest_framework import serializers
from . import models                    #数据表

数据库表

from django.db import models

# Create your models here.

class Menu(models.Model):
    name = models.CharField(max_length=32)

class Group(models.Model):
    title = models.CharField(max_length=32)
    mu = models.ForeignKey(to="Menu",default=1)

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)

    group = models.ForeignKey(to='Group')
    roles = models.ManyToManyField(to='Role')


class Role(models.Model):
    name = models.CharField(max_length=32)

a、基本操作

class UsersSerializer(serializers.Serializer):
    name = serializers.CharField()
    pwd = serializers.CharField()

class UsersView(APIView):
    def get(self,request,*args,**kwargs):
        self.dispatch
        # 方式一:
        # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
        # return Response(user_list)

        # 方式二之多对象
        # user_list = models.UserInfo.objects.all()
        # ser = UsersSerializer(instance=user_list,many=True)
        # return Response(ser.data)

        # 方式二之单对象
        user = models.UserInfo.objects.all().first()
        ser = UsersSerializer(instance=user, many=False)
        return Response(ser.data)

b、跨表操作

class UsersSerializer(serializers.Serializer):
    name = serializers.CharField()
    pwd = serializers.CharField()
    group_id = serializers.CharField()
    xxxx = serializers.CharField(source="group.title")
    x1 = serializers.CharField(source="group.mu.name")


class UsersView(APIView):
    def get(self,request,*args,**kwargs):
        self.dispatch
        # 方式一:
        # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
        # return Response(user_list)

        # 方式二之多对象
        user_list = models.UserInfo.objects.all()
        ser = UsersSerializer(instance=user_list,many=True)
        return Response(ser.data)

c、复杂的序列化

操作一

class MyCharField(serializers.CharField):
    def to_representation(self, value):
        data_list = []
        for row in value:
            data_list.append(row.name)
        return data_list

class UsersSerializer(serializers.Serializer):
    name = serializers.CharField() # obj.name
    pwd = serializers.CharField()  # obj.pwd
    group_id = serializers.CharField() # obj.group_id
    xxxx = serializers.CharField(source="group.title") # obj.group.title
    x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
    # x2 = serializers.CharField(source="roles.all") # obj.mu.name
    x2 = MyCharField(source="roles.all") # obj.mu.name

操作二

class MyCharField(serializers.CharField):
    def to_representation(self, value):
        return {'id':value.pk, 'name':value.name}

class UsersSerializer(serializers.Serializer):
    name = serializers.CharField() # obj.name
    pwd = serializers.CharField()  # obj.pwd
    group_id = serializers.CharField() # obj.group_id
    xxxx = serializers.CharField(source="group.title") # obj.group.title
    x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
    # x2 = serializers.CharField(source="roles.all") # obj.mu.name
    x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name

操作三

class UsersSerializer(serializers.Serializer):
    name = serializers.CharField() # obj.name
    pwd = serializers.CharField()  # obj.pwd
    group_id = serializers.CharField() # obj.group_id
    xxxx = serializers.CharField(source="group.title") # obj.group.title
    x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
    # x2 = serializers.CharField(source="roles.all") # obj.mu.name
    # x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
    x2 = serializers.SerializerMethodField()

    def get_x2(self,obj):
        obj.roles.all()
        role_list = obj.roles.filter(id__gt=1)
        data_list = []
        for row in role_list:
            data_list.append({'pk':row.pk,'name':row.name})
        return data_list

以上三种方式都是使用相同的视图

class UsersView(APIView):
    def get(self,request,*args,**kwargs):
        self.dispatch
        # 方式一:
        # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
        # return Response(user_list)

        # 方式二之多对象
        user_list = models.UserInfo.objects.all()
        # [obj1,obj2,obj3]
        ser = UsersSerializer(instance=user_list,many=True)
        return Response(ser.data)

d、基于model

class UsersSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"
        # fields = ['name', 'pwd','group']
        depth = 1


class UsersView(APIView):
    def get(self,request,*args,**kwargs):
        self.dispatch
        # 方式一:
        # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
        # return Response(user_list)

        # 方式二之多对象
        user_list = models.UserInfo.objects.all()
        # [obj1,obj2,obj3]
        ser = UsersSerializer(instance=user_list,many=True)
        return Response(ser.data)

e、生成url

class UsersSerializer(serializers.ModelSerializer):
    group = serializers.HyperlinkedIdentityField(view_name='detail')
    class Meta:
        model = models.UserInfo
        fields = "__all__"
        fields = ['name', 'pwd','group']
        depth = 1


class UsersView(APIView):
    def get(self,request,*args,**kwargs):
        self.dispatch
        # 方式一:
        # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
        # return Response(user_list)

        # 方式二之多对象
        user_list = models.UserInfo.objects.all()
        # [obj1,obj2,obj3]
        ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
        return Response(ser.data)

f、全局生成url

class UsersSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"

        # fields = ['id','name','pwd']

class UsersView(APIView):
    def get(self,request,*args,**kwargs):
        self.dispatch
        # 方式一:
        # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
        # return Response(user_list)

        # 方式二之多对象
        user_list = models.UserInfo.objects.all()
        # [obj1,obj2,obj3]
        ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
        return Response(ser.data)

请求数据验证

方式一

class PasswordValidator(object):
    def __init__(self, base):
        self.base = base

    def __call__(self, value):
        if value != self.base:
            message = '用户输入的值必须是 %s.' % self.base
            raise serializers.ValidationError(message)

    def set_context(self, serializer_field):
        """
        This hook is called by the serializer instance,
        prior to the validation call being made.
        """
        # 执行验证之前调用,serializer_fields是当前字段对象
        pass

class UsersSerializer(serializers.Serializer):
        name = serializers.CharField(min_length=6)
        pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])

方式二

class PasswordValidator(object):
    def __init__(self, base):
        self.base = base

    def __call__(self, value):
        if value != self.base:
            message = '用户输入的值必须是 %s.' % self.base
            raise serializers.ValidationError(message)

    def set_context(self, serializer_field):
        """
        This hook is called by the serializer instance,
        prior to the validation call being made.
        """
        # 执行验证之前调用,serializer_fields是当前字段对象
        pass

class UsersSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"
        extra_kwargs = {
            'name': {'min_length': 6},
            'pwd': {'validators': [PasswordValidator(666), ]}
        }

使用:

class UsersView(APIView):
    def get(self,request,*args,**kwargs):
        self.dispatch
        # 方式一:
        # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
        # return Response(user_list)

        # 方式二之多对象
        user_list = models.UserInfo.objects.all()
        # [obj1,obj2,obj3]
        ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
        return Response(ser.data)

    def post(self,request,*args,**kwargs):
        ser = UsersSerializer(data=request.data)
        if ser.is_valid():
            print(ser.validated_data)
        else:
            print(ser.errors)
        return Response('...')

 8、分页

a、基于limitoffsetpagination做分页

class P1(LimitOffsetPagination):
    max_limit = 3
    default_limit = 2
    limit_query_param = 'limit'
    offset_query_param = 'offset'

b、基于PageNumberPagination做分页

class P2(PageNumberPagination):
    # 每页显示的数据条数
    max_page_size = 5
    page_size = 2
    page_size_query_param = 'size'
    # 页码
    page_query_param = 'page'

c、基于CursorPagination做分页

class P3(CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 2
    ordering = 'id'

需要用到的模块

from django.shortcuts import render
from rest_framework import views
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination,PageNumberPagination,CursorPagination
from api import models
from api.serializers.index import IndexSerializer

基于视图实现

class IndexView(views.APIView):
    def get(self,request,*args,**kwargs):
        user_list = models.UserInfo.objects.all()            #查询到所有的数据
        p1 = P1()                                            #实例化显示的那个对象
        page_user_list = p1.paginate_queryset(queryset=user_list, request=request, view=self)     #经过处理后的数据列表
        ser = IndexSerializer(instance=page_user_list, many=True)       
        return Response(ser.data) # 不含上一页和下一页                 
        # return p1.get_paginated_response(ser.data) # 含上一页和下一页

基于视图使用对象的方式实现

class BaseResponse(object):
    def __init__(self,code=1000,data=None,error=None):
        self.code = code
        self.data = data
        self.error = error
class IndexView(views.APIView):
    def get(self,request,*args,**kwargs):
        ret = BaseResponse()              #基于对象的形式展示
        try:
            user_list = models.UserInfo.objects.all()
            p1 = P1()
            page_user_list = p1.paginate_queryset(queryset=user_list,request=request,view=self)
            ser = IndexSerializer(instance=page_user_list,many=True)
            ret.data = ser.data         #给对象赋值
            ret.next = p1.get_next_link()      #上一页下一页链接
        except Exception as e:
            ret.code= 1001
            ret.error = 'xxxx错误'
        return Response(ret.__dict__)           #以字典的形式返回

 9、视图

1. APIView

class IndexView(views.APIView):
    def get(self, request, *args, **kwargs):
        user_list = models.UserInfo.objects.all()
        ser = IndexSerializer(instance=user_list,many=True)
        return Response(ser.data)

2.GenericAPIView

class IndexView(generics.GenericAPIView):
    queryset = models.UserInfo.objects.all()
    serializer_class = IndexSerializer
    pagination_class = P2
    def get(self,request,*args,**kwargs):
        user_list = self.get_queryset()
        p1 = self.paginator
        data = p1.paginate_queryset(queryset=user_list,request=request,view=self)
        ser = self.get_serializer(instance=data,many=True)
        return p1.get_paginated_response(ser.data)

3. GenericViewSet(ViewSetMixin, generics.GenericAPIView)

路由修改
urlpatterns = [
                url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})),]
                
from rest_framework.viewsets import GenericViewSet
class IndexView(GenericViewSet):
    queryset = models.UserInfo.objects.all()
    serializer_class = IndexSerializer
    pagination_class = P2
    def list(self,request,*args,**kwargs):
        print("这里是list请求")
        return Response("...")
    def retrieve(self,request,*args,**kwargs):
        print("这里是post请求")
        return Response("...")
    def create(self,request,*args,**kwargs):
        print("这里是put请求")
        return Response("...")
        




自定义:

    增
        POST
        /users/
    删
        DELETE
        /users/1/
    改
        PUT
        /users/1/
        
        patch
        /users/1/
    查
        GET
        /users/ 
        GET
        /users/1/
                            
urlpatterns = [
    url(r'^index/$', views.IndexView.as_view()),
    url(r'^index/(?P<pk>\d+)$', views.IndexView.as_view({'get':'retrieve'})),
]
                            
class IndexView(views.APIView):

    def get(self,request,*args,**kwargs):
        pk = kwargs.get('pk')
        if pk:
            pass # 获取单条信息
        else:
            pass # 获取列表信息

    def post(self,request,*args,**kwargs):
        pass

    def put(self,request,*args,**kwargs):
        pass

    def patch(self,request,*args,**kwargs):
        pass

    def delete(self,request,*args,**kwargs):
        pass

4.ModelViewSet

ModelViewSet(mixins.CreateModelMixin,
            mixins.RetrieveModelMixin,
            mixins.UpdateModelMixin,
            mixins.DestroyModelMixin,
            mixins.ListModelMixin,
            GenericViewSet)    
视图:
urlpatterns = [
    url(r'^user/$',views.IndexView.as_view({"get":"list","post":"create"})),
    url(r'^user/(?P<pk>\d+)/$',views.IndexView.as_view({"get":"retrieve","delete":"destroy","put":"update","patch":"partial_update"}))
]
from rest_framework.viewsets import ModelViewSet

class IndexView(ModelViewSet):
    queryset = models.UserInfo.objects.all()
    serializer_class = IndexSerializer
    pagination_class = P2        

10、路由和渲染器

第一类:
    # http://127.0.0.1:8000/api/v1/auth/
    url(r'^auth/$', views.AuthView.as_view()),
    # http://127.0.0.1:8000/api/v1/auth.json # 想要让页面显示json格式
    url(r'^auth\.(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
    # http://127.0.0.1:8000/api/v1/auth/1/
    url(r'^auth/(?P<pk>\d+)/$', views.AuthView.as_view()),
    # http://127.0.0.1:8000/api/v1/auth/1.json
    url(r'^auth/(?P<pk>\d+)\.(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
    class AuthView(views.APIView):

        def get(self,request,*args,**kwargs):
            return Response('...')
第二类:
    url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})),
    url(r'^index/\.(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'list','post':'create'})),
    url(r'^index/(?P<pk>\d+)/$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
    url(r'^index/(?P<pk>\d+)\.(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),

    class IndexView(viewsets.ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2
第三类: 
    router = DefaultRouter()
    router.register('index',views.IndexViewSet)
    urlpatterns = [
        url(r'^', include(router.urls)),
    ]
    
    
    class IndexViewSet(viewsets.ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2
        
        
        
    class IndexSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
.渲染器
renderer_classes = [JSONRenderer,BrowsableAPIRenderer]     #好看的页面默认返回的是这两个,如果只想返回json则    JSONRenderer    

 

 ##

给query_set 新增一个扩展字段,并按照扩展字段进行排序(需要更新serializer,不需要更新model)

 

 

 

 

 

 

 

未完待续。。。。

 

posted @ 2018-02-05 14:34 前方、有光 阅读(...) 评论(...) 编辑 收藏