Django Restful Framework【第四篇】版本、解析器、序列化和请求数据验证

一、版本

程序也来越大时,可能通过版本不同做不同的处理

没用rest_framework之前,我们可以通过以下这样的方式去获取。

class UserView(APIView):
    def get(self,request,*args,**kwargs):
        version = request.query_params.get(‘version‘)
        print(version)
        if version==‘v1‘:
            #如果版本是v1
            ret = {
                ‘code‘:111,
                ‘msg‘:‘版本一的内容‘
            }

        elif version==‘v2‘:
            # 如果是v2
            ret = {
                ‘code‘: 112,
                ‘msg‘: ‘版本二的内容‘
            }
        else:
            ret = {
                ‘code‘: 0,
                ‘msg‘: ‘不支持其他版本‘
            }
        return Response(ret)

现在我们来用rest_framework实现一下,有两种方式

1、基于url的方式

 #基于url传参的形式
     versioning_class = QueryParameterVersioning
    #http://127.0.0.1:8080/api/users/?version=v2

#基于url的形式
  versioning_class = URLPathVersioning
  #http://127.0.0.1:8080/api/v1/users/

具体步骤

settings配置

REST_FRAMEWORK = {
    ‘DEFAULT_VERSION‘: ‘v1‘,  #默认的版本
    ‘ALLOWED_VERSIONS‘: [‘v1‘,‘v2‘],  #允许的版本
    ‘VERSION_PARAM‘: ‘version‘,
}

urls.py

from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
    url(r‘^api/(?P<version>[v1|v2]+)/‘, include(‘api.urls‘), name=‘users-list‘),
]

  

urls.py

from api import views
urlpatterns = [
    # url(r‘^users/‘, views.UserView.as_view()),
    url(r‘^users/‘, views.UserView1.as_view()),

]

  

views.py

class UserView1(APIView):
    #基于url传参的形式
    # versioning_class = QueryParameterVersioning
    #http://127.0.0.1:8080/api/users/?version=v2

    #基于url的形式
    #http://127.0.0.1:8080/api/v1/users/
    versioning_class = URLPathVersioning
    def get(self,request,*args,**kwargs):
        # self.dispatch
        print(request.version)  #打印的是版本
        print(request.versioning_scheme)  #打印的是对象
        if request.version==‘v2‘:
            return Response(‘我是版本二‘)
        elif request.version==‘v1‘:
            return Response(‘我是版本一‘)
        else:
            return Response(‘去去去‘)

  

注:在配置的时候

REST_FRAMEWORK = {
                ‘VERSION_PARAM‘:‘version‘,
                ‘DEFAULT_VERSION‘:‘v1‘,
                ‘ALLOWED_VERSIONS‘:[‘v1‘,‘v2‘],
                # ‘DEFAULT_VERSIONING_CLASS‘:"rest_framework.versioning.HostNameVersioning"            #如果加上这个配置就不用versioning_class = QueryParameterVersioning这样在指定了,
           ‘DEFAULT_VERSIONING_CLASS‘:"rest_framework.versioning.URLPathVersioning" }

附加:restful提供的反向生成

#http://127.0.0.1:8080/api/v1/users/

#urls.py
#分发路由
urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
    url(r‘^api/(?P<version>[v1|v2]+)/‘, include(‘api.urls‘)),
]

#api.urls.py
urlpatterns = [
    url(r‘^users/‘, views.UserView1.as_view(), name=‘users-list‘),
]

#views.py
导入类
from rest_framework.reverse import reverse
url = request.versioning_scheme.reverse(viewname=‘users-list‘,request=request)
        print(url)

我们自己用django实现的,当前版本不一样的时候可以用这种方式

 from django.urls import reverse
        url = reverse(viewname=‘users-list‘,kwargs={‘version‘:‘v2‘}) #指定的是v2就是v2,当你路径中输入v1的时候还是v2的路径
        print(url) #/api/v2/users/

2、基于子域名传参

#分发url
            urlpatterns = [
                #url(r‘^admin/‘, admin.site.urls),
                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"
            }

            # C:\Windows\System32\drivers\etc
            # vim /etc/hosts
            127.0.0.1    v1.luffy.com
            127.0.0.1    v2.luffy.com

            #配置ALLOWED_HOSTS = [‘*‘]

  

如果遇到这样的错误

这是由于没有允许,解决办法,在settings里面配置一下

ALLOWED_HOSTS = [‘*‘]

二、解析器:reqest.data取值的时候才执行

对请求的数据进行解析:是针对请求体进行解析的。表示服务器可以解析的数据格式的种类

django中的发送请求

#如果是这样的格式发送的数据,在POST里面有值
Content-Type: application/url-encoding.....
    request.body
    request.POST

#如果是发送的json的格式,在POST里面是没有值的,在body里面有值,可通过decode,然后loads取值
Content-Type: application/json.....
    request.body
    request.POST

为了这种情况下每次都要decode,loads,显得麻烦,所以才有的解析器。弥补了django的缺点

#具体讲解
客户端:
            Content-Type: application/json
            ‘{"name":"alex","age":123}‘

        服务端接收:
            读取客户端发送的Content-Type的值 application/json

            parser_classes = [JSONParser,FormParser]  #表示服务器可以解析的数据格式的种类
            media_type_list = [‘application/json‘,‘application/x-www-form-urlencoded‘]

            如果客户端的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‘,
                        ‘rest_framework.parsers.FormParser‘,
                    ]
                }

                class UserView(APIView):
                    def get(self,request,*args,**kwargs):
                        return Response(‘ok‘)
                    def post(self,request,*args,**kwargs):
                        print(request.data)  #以后取值就在这里面去取值
                        return Response(‘...‘)

  

传上传文件

urls.py

from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r‘test/(?P<filename>[^/]+)‘, TestView.as_view(), name=‘test‘),
]

views.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FileUploadParser

class TestView(APIView):
    parser_classes = [FileUploadParser, ]

    def post(self, request, filename, *args, **kwargs):
        print(filename)
        print(request.content_type)

        # 获取请求的值,并使用对应的JSONParser进行处理
        print(request.data)
        # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
        print(request.POST)
        print(request.FILES)
        return Response(‘POST请求,响应内容‘)

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

upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
    <input type="text" name="user" />
    <input type="file" name="img">

    <input type="submit" value="提交">

</form>
</body>
</html>

全局使用

settings.py

REST_FRAMEWORK = {
    ‘DEFAULT_PARSER_CLASSES‘:[
        ‘rest_framework.parsers.JSONParser‘
        ‘rest_framework.parsers.FormParser‘
        ‘rest_framework.parsers.MultiPartParser‘
    ]

}

三、序列化

序列化用于对用户请求数据进行验证和数据进行序列化(为了解决queryset序列化问题)。

那什么是序列化呢?序列化就是把对象转换成字符串,反序列化就是把字符串转换成对象

models.py

from django.db import models

# Create your models here.
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 Menu(models.Model):
    name = models.CharField(max_length=21)

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

1、基本操作

views.py

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import BaseVersioning
from rest_framework.versioning import QueryParameterVersioning  #获取version的值
from rest_framework.versioning import URLPathVersioning #支持版本
from rest_framework.versioning import HostNameVersioning
from rest_framework.parsers import JSONParser  #解析器
from rest_framework import serializers
from app03 import models
class UsersSerializer(serializers.Serializer):
    name = serializers.CharField()  #字段名字
    pwd = serializers.CharField()

class UserView(APIView):
    def get(self,request,*args,**kwargs):
        # 方式一实现
        # user_list = models.UserInfo.objects.values(‘name‘,‘pwd‘,‘group__mu‘,‘group__title‘)
        # print(type(user_list))
        # return Response(user_list)

        # 方式二之多对象
        # user_list = models.UserInfo.objects.all()  #直接这样查会报错,借助他提供的系列化
        # ser = UsersSerializer(instance=user_list,many=True) #可允许多个
        # # print(type(ser))  #<class ‘rest_framework.serializers.ListSerializer‘>
        # print(ser.data)  #返回的是一个有序字典

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

        return Response(ser.data)

  

2、跨表

 x1 = serializers.CharField(source=‘group.mu.name‘) 

   如果你想跨表拿你任何需要的数据,都可以用上面的这种操作,内部做判断,如果可用内部就加括号调用了

Views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from app03 import models
class UsersSerializer(serializers.Serializer):
    name = serializers.CharField()  #字段名字
    pwd = serializers.CharField()
    # group = serializers.CharField()  #会显示对象
    # group_id = serializers.CharField()  #会显示id
    x1 = serializers.CharField(source=‘group.mu.name‘)
    roles = serializers.CharField(source=‘roles.all‘) #多对多关系的这样查出的是queryset对象

class UserView2(APIView):
    ‘‘‘跨表操作‘‘‘
    def get(self,request,*args,**kwargs):

        user = models.UserInfo.objects.all()
        ser = UsersSerializer(instance=user,many=True)

        return Response(ser.data)

  

3、复杂序列化

解决方案一:

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") #  多对多关系的这样查出的是queryset对象
    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):  #get_字段名
        print(obj)   ##UserInfo object
        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

  

4、基于Model

class UsersSerializer(serializers.ModelSerializer):
x1 = serializers.CharField(source=‘name‘)
group = serializers.HyperlinkedIdentityField(view_name=‘detail‘)
class Meta:

    model = models.UserInfo
    # fields = "__all__"
    fields = [‘name‘,‘pwd‘,‘group‘,‘x1‘]  #自定义字段的时候注意要指定source,scource里面的数据必须是数据库有的数据
    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)

Views.py

  

5、生成URL

views.py

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)

 

from django.conf.urls import url,include
from django.contrib import admin
from app03 import views
urlpatterns = [

    url(r‘^users4/‘, views.UserView4.as_view(), name=‘xxx‘), #吧users4的group的值反向生成users5的url
    url(r‘^users5/(?P<pk>.*)‘, views.UserView5.as_view(), name=‘detail‘),  #必须叫pk
    # url(r‘^users4/(?P<pk>.*)‘, views.UserView4.as_view(), name=‘detail‘),
]

6、全局生成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)

  

四、请求数据验证:

a、自己手写

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‘)])

  

b、基于model

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 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(‘...‘)

钩子函数

def validate_字段(self,validated_value):
       raise ValidationError(detail=‘xxxxxx‘)
       return validated_value
                        

原文地址:https://www.cnblogs.com/xiaohema/p/8456887.html

时间: 2024-10-06 21:35:41

Django Restful Framework【第四篇】版本、解析器、序列化和请求数据验证的相关文章

django restful framework 一对多方向更新数据库

目录 django restful framework 序列化 一 . 数据模型: models 二. 序列化: serializers 三, 视图: views 四, 路由: urls 五. 测试 : test django restful framework 序列化 案例: 一个网域domain可以绑定多台服务器主机assets, 但是一台服务器只能绑定一个网域. 数据模型之间关系适用于一对多. 一 . 数据模型: models 定义 assets 模型:apps/assets/models

3- vue django restful framework 打造生鲜超市 - model设计和资源导入

3- vue django restful framework 打造生鲜超市 - model设计和资源导入 使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支付宝支付(暂不支持微信支付),支持手机短信验证码注册, 支持第三方登录.集成了sentry错误监控系统. 本小节内容: model设计与资源引入 资源初始化 数据库设计,数据表结构 新建虚拟环境 mkvirtualenv -p=D:\softEnv

Django Restful Framework【第三篇】认证、权限、限制访问频率

一.认证 认证请求头 views.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.permissions import

Django Restful Framework【第五篇】分页、视图、路由、渲染器

一.分页 试问如果当数据量特别大的时候,你是怎么解决分页的? 方式a.记录当前访问页数的数据id 方式b.最多显示120页等 方式c.只显示上一页,下一页,不让选择页码,对页码进行加密 1.基于limit offset 做分页 from rest_framework.pagination import LimitOffsetPagination urls.py urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/(?P<v

爬虫笔记(四)------关于BeautifulSoup4解析器与编码

前言:本机环境配置:ubuntu 14.10,python 2.7,BeautifulSoup4 一.解析器概述 如同前几章笔记,当我们输入: soup=BeautifulSoup(response.body) 对网页进行析取时,并未规定解析器,此时使用的是python内部默认的解析器“html.parser”. 解析器是什么呢? BeautifulSoup做的工作就是对html标签进行解释和分类,不同的解析器对相同html标签会做出不同解释. 举个官方文档上的例子: BeautifulSoup

Restful framework【第一篇】RESTful 规范

什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态 REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” 所有的数据,

Django Restful Framework

你在浏览器中输入了一个地址的时候发生了什么事情? 1.HOST 2.DNS 3.HTTP/HTTPS协议 发送一个协议 4.进入了实现了WSGI协议的服务器(wsgiref uwsgi(C语言实现,多线程,多进程,PHP,TOMCAT)) 5.请求进入Django 6. 前后端不分离:中间件->路由分发->对应的视图函数->找到模板,渲染数据-> 返回模板的字符串 前后端分析:中间件->路由分发->返回JSON数据 Django源代码解读 graph TD A[路由匹配

Restful Framework (四)

目录 一.分页 二.视图 三.路由 四.渲染器 一.分页 回到顶部 试问如果当数据量特别大的时候,你是怎么解决分页的? 方式a.记录当前访问页数的数据id 方式b.最多显示120页等 方式c.只显示上一页,下一页,不让选择页码,对页码进行加密 1.基于limit offset 做分页 from rest_framework.pagination import LimitOffsetPagination 1 urlpatterns = [ 2 url(r'^admin/', admin.site.

Django REST framework 第四章 Authentication

到目前为止,撰写的API没有任何限制关于谁能更新.删除snippet. 我们更想要一些高级行为来确保: 1.代码段总是跟创建者有关联 2.只要认证通过的用户才能创建 3.只有创建者有权限更新或者删除 4.没有认证的请求应该有且只有完全的只读权限 Adding information to our model 我们打算在Snippet模型类上做一些改变.首先,添加一些字段,其中之一用来代表创建这个code的用户.其他的字段将用于存储代码中突出显示的HTML表示形式. 添加下面两个字段到Snippe