django rest framework(3)

django rest framework(3)

目錄html

1、版本python

2、解析器web

3、序列化數據庫

4、請求數據驗證django


1、版本json

程序也來越大時,可能經過版本不一樣作不一樣的處理vim

沒用rest_framework以前,咱們能夠經過如下這樣的方式去獲取。api

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)
View Code

如今咱們來用rest_framework實現一下,有兩種方式服務器

一、基於url的方式restful

複製代碼
 #基於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/
複製代碼

具體步驟

1 REST_FRAMEWORK = {
2     'DEFAULT_VERSION': 'v1',  #默認的版本
3     'ALLOWED_VERSIONS': ['v1','v2'],  #容許的版本
4     'VERSION_PARAM': 'version',
5 }
一、配置
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
urls.py
1 from api import views
2 urlpatterns = [
3     # url(r'^users/', views.UserView.as_view()),
4     url(r'^users/', views.UserView1.as_view()),
5 
6 ]
urls.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('去去去')

views.py
views.py

注:在配置的時候

複製代碼
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)

restfoamework反向解析
restfoamework反向解析

咱們本身用django實現的,當前版本不同的時候能夠用這種方式

 from django.urls import reverse
        url = reverse(viewname='users-list',kwargs={'version':'v2'}) #指定的是v2就是v2,當你路徑中輸入v1的時候仍是v2的路徑
        print(url) #/api/v2/users/

二、基於子域名傳參

#分發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 = ['*']

 

2、解析器: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('...')

具體講解
具體講解

傳上傳文件

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
6 ]
urls.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請求,響應內容')

views.py
Views.py
<!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>

upload.html
upload.html

全局使用

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

}

settings.py
settings.py

3、序列化

序列化用於對用戶請求數據進行驗證和數據進行序列化(爲了解決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)
複製代碼

一、基本操做

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)

views.py
views.py

二、跨表

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

   若是你想跨表拿你任何須要的數據,均可以用上面的這種操做,內部作判斷,若是可用內部就加括號調用了

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)

Views.py
Views.py

三、複雜序列化

解決方案一:

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

Views.py
Views.py

解決方案二:

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

Views.py
Views.py

解決方案三(推薦使用)

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
    

Views.py
Views.py

四、基於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
Views.py

五、生成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)

views.py
views.py
複製代碼
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'),
]
複製代碼

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

views.py
Views.py

4、請求數據驗證:

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

views.py
views.py

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.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"
        #自定義驗證規則
        extra_kwargs = {
            'name': {'min_length': 6},
            'pwd': {'validators': [PasswordValidator(666), ]}
        }

views.py
views.py

使用

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

viewS.py
viewS.py

鉤子函數

def validate_字段(self,validated_value):
       raise ValidationError(detail='xxxxxx')
       return validated_value
                        
相關文章
相關標籤/搜索