zoukankan      html  css  js  c++  java
  • Django Rest Framework框架

    Django Rest Framework框架介绍

      API接口简称API,它与网站路由的实现原理相同。当用户使用GET或者POST方式访问API时,API以JSON或字符串的数据内容返回给用户,网站的路由返回的是HTML网页信息,这与API返回的数据格式有所不同

    1.1  DRF的安装与配置

      开发网站的API可以在视图函数中使用响应类JsonResponse实现,它将字典格式的数据作为响应内容。使用响应类JsonResponse开发API需要根据用户请求信息构建字典格式的数据内容,数据构建的过程可能涉及模型的数据查询、数据分页处理等业务逻辑,这种方式开发API很容易造成代码冗余,不利于功能的变更和维护。

      为了简化API的开发过程,我们可以使用Django Rest Framework框架实现API开发。使用框架开发不仅能减少代码冗余,还可以规范代码的编写格式,这对企业级开发来说很有必要,毕竟每个开发人员的编程风格存在一定的差异,开发规范化可以方便其他开发人员查看和修改。

      在使用Django Rest Framework框架之前,首先安装Django Rest Framework框架,建议使用pip完成安装,安装指令如下:

    pip install djangorestframework

      框架安装成功后,通过简单的例子来讲述如何在Django中配置Django Rest Framework的功能。以MyDjango为例,在项目应用index中创建serializers.py文件,该文件用于定义Django Rest Framework的序列化类;然后在MyDjango的settings.py中设置功能配置,功能配置如下:

    #事先创建一个django项目和index的app应用,再settings.py里面添加如下:
    INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'index.apps.IndexConfig',
      #添加Django Rest Framework框架
    'rest_framework' ]
    #Django Rest Framework框架设置信息
    #分页设置
    REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS':
    'rest_framework.pagination.PageNumberPagination',
               #每页显示多少条数据
    'PAGE_SIZE': 2
    }

      上述配置信息用于实现Django Rest Framework的功能配置,配置说明如下:

        (1)在INSTALLED_APPS中添加API框架的功能配置,这样能使Django在运行过程中自动加载Django Rest Framework的功能。

        (2)配置属性REST_FRAMEWORK以字典的形式表示,用于设置Django Rest Framework的分页功能。

      完成settings.py的配置后,下一步定义项目的数据模型。在index的models.py中分别定义模型PersonInfo和Vocation,代码如下:

    #index的models.py
    from django.db import models
    
    # Create your models here.
    
    class PersonInfo(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=20)
        age = models.IntegerField()
        hireDate = models.DateField()
    
        def __str__(self):
            return self.name
    
        class Meta:
            verbose_name = '人员信息'
            verbose_name_plural = verbose_name
    
    
    class Vocation(models.Model):
        id = models.AutoField(primary_key=True)
        job = models.CharField(max_length=20)
        title = models.CharField(max_length=20)
        payment = models.IntegerField(null=True,blank=True)
        name = models.ForeignKey(PersonInfo, on_delete=models.Case)
        
        def __str__(self):
            return str(self.id)
        
        class Meta:
            verbose_name = '职业信息'
            verbose_name_plural = verbose_name
    index/models.py

      将定义好的模型执行数据迁移,在项目的db.sqlite3数据库文件中生成数据表,并对数据表index_personinfo和index_vocation添加数据内容,如下图所示:

     数据表index_personinfo和index_vocation

    1.2  序列化类Serializer

      项目环境搭建完成后,我们将使用Django Rest Framework快速开发API。首先在项目应用index的serializers.py中定义序列化类MySerializer,代码如下:

    #index的serializers.py
    from rest_framework import serializers
    from .models import PersonInfo, Vocation
    
    #定义Serializer类
    #设置模型Vocation的字段name的下拉内容
    nameList = PersonInfo.objects.values('name').all()
    NAME_CHOICES = [item['name'] for item in nameList]
    
    class MySerializer(serializers.Serializer):
        id = serializers.IntegerField(read_only=True)
        job = serializers.CharField(max_length=100)
        title = serializers.CharField(max_length=100)
        payment = serializers.CharField(max_length=100)
        #name=serializers.ChoiceField(choices=NAME_CHOICES,default=1)
        #模型Vocation的字段name是外键字段,它指向模型PersonInfo
        #因此,外键字段可以使用PrimaryKeyRelatedField
        name = serializers.PrimaryKeyRelatedField(queryset=nameList)
        #重写create函数,将API数据保存到数据表index_vocation中
        def create(self, validated_data):
            return Vocation.objects.create(**validated_data)
    
        #重写update函数,将API数据更新到数据表index_vocation中
        def update(self, instance, validated_data):
            return instance.update(**validated_data)
    index/serializers.py

      自定义序列化类MySerializer继承父类Serializer,父类Serializer是由Django Rest Framework定义的,它的定义过程与表单类Form十分相似。在PyCharm里打开父类Serializer的源码文件,分析序列化类Serializer的定义过程。

      Serializer继承父类BaseSerializer,装饰器add_metaclass设置元类SerializerMetaclass。我们以流程图的形式说明Serializer的继承关系,如下图:

    Serializer的继承关系

       自定义序列化类MySerializer的字段对应模型Vocation的字段,序列化字段的数据类型可以在Django Rest Framework的源码文件fields.py中找到定义过程,他们都继承父类Field,序列化字段的数据类型与表单字段的数据类型相似。

      在定义序列化字段的时候,每个序列化字段允许设置参数信息,我们分析父类Field的初始化参数,他们适用于所有序列化字段的参数设置,参数说明如下:

        read_only:设置序列化字段的只读属性

        write_only:设置序列化字段的编辑属性

        required:设置序列化字段的数据是否为空,默认值为True

        default:设置序列化字段的默认值

        initial:设置序列化字段的初始值

        source:为序列化字段指定一个模型字段来源,如(email='user.email')

        label:用于生成label标签的网页内容

        help_text:设置序列化字段的帮助提示信息

        style:以字典格式化表示,控制模板引擎如何渲染序列化字段

        error_messages:设置序列化字段的错误信息,以字段格式表示,包含null、blank、invalid、invalid_choice、unique等键值

        validators:与表单类的validators相同,这是自定义数据验证规则,以列表格式表示,列表元素为数据验证的函数名

        allow_null:设置序列化字段是否为None,若为True,则序列化字段的值允许为None

      自定义序列化类MySerializer还定义了关系字段name,重写了父类BaseSerializer的create和update函数。关系字段可以在源码文件relations.py中找到定义过程,每个关系字段都有代码注释说明,本节不再重复讲述。

      下一步使用序列化类MySerializer实现API开发,在index的urls.py中分别定义路由myDef和路由myClass,路由信息的代码如下:

    #index的urls.py
    from django.urls import path
    from .views import *
    
    urlpatterns = [
        #视图函数
        path('', vocationDef, name='myDef'),
        #视图类
        path('myClass/', vocationClass.as_view(), name='myClass'),
    ]

      路由myDef对应视图函数vocationDef,它以视图函数的方式使用MySerializer实现模型Vocation的API接口;路由myClass对应视图。类vocationClass,它以视图类的方式使用MySerializer实现模型Vocation的API接口。因此,视图函数vocationDef和视图类vocationClass的定义过程如下:

    #index的views.py
    from django.shortcuts import render
    from .models import PersonInfo, Vocation
    from .serializers import MySerializer
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from rest_framework.pagination import PageNumberPagination
    from rest_framework.decorators import api_view
    # Create your views here.
    
    
    @api_view(['GET', 'POST'])
    def vocationDef(request):
        if request.method == 'GET':
            q = Vocation.objects.all()
            #分页查询,需要在settings.py中设置REST_FRAMEWORK属性
            pg = PageNumberPagination()
            p=pg.paginate_queryset(queryset=q, request=request)
            #将分页后的数据传递给MySerializer,生成JSON数据对象
            serializer = MySerializer(instance=p, many=True)
            #返回对象Response由Django Rest Framework实现
            return Response(serializer.data)
        elif request.method == 'POST':
            #获取请求数据
            data = request.data
            id = data['name']
            data['name'] = PersonInfo.objects.filter(id=id).first()
            instance = Vocation.objects.filter(id=data.get('id', 0))
            if instance:
                #修改数据
                MySerializer().update(instance, data)
            else:
                #创建数据
                MySerializer().create(data)
            return Response('Done', status=status.HTTP_201_CREATED)
    
    
    class vocationClass(APIView):
        #GET请求
        def get(self, request):
            q = Vocation.objects.all()
            #分页查询,需要在settings.py中设置REST_FRAMEWORK属性
            pg = PageNumberPagination()
            p = pg.paginate_queryset(queryset=q, request=request, view=self)
            #将分页后的数据传递给MySerializer,生成JSON数据对象
            serializer = MySerializer(instance=p, many=True)
            #返回对象Response由Django Rest Framework实现
            return Response(serializer.data)
    
        #POST请求
        def post(self, request):
            data = request.data
            id = data['name']
            data['name'] = PersonInfo.objects.filter(id=id).first()
            instance = Vocation.objects.filter(id=data.get('id', 0))
            if instance:
                #修改数据
                MySerializer().update(instance, data)
            else:
                #创建数据
                MySerializer().create(data)
            return Response('Done', status.HTTP_201_CREATED)
    index/views.py

      视图函数vocationDef和视图类vocationClass实现的功能是一致的,若使用视图函数开发API接口,则必须对视图函数使用装饰器api_view;若使用视图类,则必须继承父类APIView,这是Django Rest Framework明确规定的。上述的视图函数vocationDef和视图类vocationClass对GET请求和POST请求进行不同的处理。

      当用户在浏览器上访问路由myDef或路由myClass的时候,视图函数vocationDef或视图类vocationClass将接收GET请求,该请求的处理过程说明如下:

        (1)视图函数vocationDef或视图类vocationClass查询模型Vocation所有数据,并将数据进行分页处理。

        (2)分页功能有Django Rest Framework的PageNumberPagination实现,他是在Django内置分页功能的基础上进行封装的,分页属性设置在settings.py的REST_FRAMEWORK中。

        (3)分页后的数据传递给序列化类MySerializer,转化成JSON数据,最后由Django Rest Framework框架的Response完成用户响应。

      运行MyDjango项目,分别访问路由myDef和路由myClass,发现两者返回的网页内容是一致的。如果在路由地址中设置请求参数page,就可以获取某分页的数据信息,如下图:

       用户向路由myDef或路由myClass发送POST请求时,视图函数vocationDef或视图类vocationClass的处理过程说明如下:

        (1)视图函数vocationDef或视图类vocationClass获取请求参数,将请求参数id作为模型字段id的查询条件,在模型Vocation中进行数据查询

        (2)如果存在查询对象,就说明模型Vocation已存在相应的数据信息,当前POST请求将视为修改模型Vocation的已有数据。

        (3)如果不存在查询对象,就把当前请求的数据信息添加在模型Vocation中

      在下图的网页正下方找到Content文本框,以模型Vocation的字段编写单个JSON数据,单击"POST"按钮即可实现数据的新增或修改

     1.3  模型序列化类ModelSerializer

      序列化类Serializer可以与模型结合使用,从而实现模型的数据读写操作。但序列化类Serializer定义的字段必须与模型字段相互契合,否则在使用过程中很容易提示异常信息。为了简化序列化类Serializer的定义过程,Django Rest Framework定义了模型序列化类ModelSerializer,它与模型表单ModelForm的定义和使用十分相似。

      以1.2小节的MyDjango为例,将自定义的MySerializer改为VocationSerializer,序列化类VocationSerializer继承父类ModelSerializer,它能与模型Vocation完美结合,无须开发者定义序列化字段。在index的serializers.py中定义VocationSerializer,代码如下:

    class VocationSerializer(serializers.ModelSerializer):
        class Meta:
            model = Vocation
            fields = '__all__'
            #fields=('id','job','title','payment','name')

      分析VocationSerializer得知,属性model将模型Vocation与ModelSerializer进行绑定;属性fields用于设置哪些模型字段转化为序列化字段,属性值__all__代表模型所有字段转化为序列化字段,如果只设置部分模型字段,属性fields的值就可以使用元组或列表表示,元组或列表的每个元素代表一个模型字段。

      下一步重新定义视图函数vocationDef和视图类vocationClass,使用模型序列化类VocationSerializer实现模型Vocation的API接口。视图函数vocationDef和视图类vocationClass的代码如下:

    from django.shortcuts import render
    from .models import PersonInfo, Vocation
    from .serializers import VocationSerializer
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from rest_framework.pagination import PageNumberPagination
    from rest_framework.decorators import api_view
    
    
    @api_view(['GET', 'POST'])
    def vocationDef(request):
        if request.method == 'GET':
            q = Vocation.objects.all().order_by('id')
            #分页查询,需要在settings.py中设置REST_FRAMEWORK属性
            pg = PageNumberPagination()
            p=pg.paginate_queryset(queryset=q, request=request)
            #将分页后的数据传递给MySerializer,生成JSON数据对象
            serializer = VocationSerializer(instance=p, many=True)
            # 返回对象Response由Django Rest Framework实现
            return Response(serializer.data)
        elif request.method == 'POST':
            #获取请求数据
            id = request.data.get('id', 0)
            #判断请求参数id在模型Vocation中是否存在
            #若存在,则执行数据修改;否则新增数据
            operation = Vocation.objects.filter(id=id).first()
            #数据验证
            serializer = VocationSerializer(data=request.data)
            if serializer.is_valid():
                if operation:
                    data = request.data
                    id = data['name']
                    data['name'] = PersonInfo.objects.filter(id=id).first()
                    serializer.update(operation, data)
                else:
                    # 保存到数据库
                    serializer.save()
                # 返回对象Response由Django Rest Framework实现
                return Response(serializer.data)
            return Response(serializer.errors, status=404)
    
    
    class vocationClass(APIView):
        #GET请求
        def get(self, request):
            q = Vocation.objects.all().order_by('id')
            #分页查询,需要在settings.py中设置REST_FRAMEWORK属性
            pg = PageNumberPagination()
            p = pg.paginate_queryset(queryset=q, request=request, view=self)
            serializer = VocationSerializer(instance=p, many=True)
            #返回对象Response由Django Rest Framework实现
            return Response(serializer.data)
    
        #POST请求
        def post(self, request):
            #获取请求数据
            id = request.data.get('id', 0)
            operation = Vocation.objects.filter(id=id).first()
            serializer = VocationSerializer(data=request.data)
            #数据验证
            if serializer.is_valid():
                if operation:
                    data = request.data
                    id = data['name']
                    data['name'] = PersonInfo.objects.filter(id=id).first()
                    serializer.update(operation, data)
                else:
                    #保存到数据库
                    serializer.save()
                #返回对象Response由Django Rest Framework实现
                return Response(serializer.data)
            return Response(serializer.errors, status=404)
    index/views.py

      视图函数vocationDef和视图类vocationClass的业务逻辑与1.2小节的业务逻辑是相同的,而对于POST请求的处理过程,本节与1.2小节实现的功能是一致,但使用的函数方法有所不同。

    1.4  序列化的嵌套使用

      在开发过程中,我们需要对多个JSON数据进行嵌套使用,比如将模型PersonInfo和Vocation的数据组合存放在同一个JSON数据中,两个模型的数据通过外键字段name进行关联。

      模型之间必须存在数据关系才能实现数据嵌套,数据关系可以是一对一、一对多或多对多的,不同的数据关系对数据嵌套的读写财政会有细微的差异。以1.3小结的MyDJnaog为例,在index的serializers.py中定义PersonInfoSerializer和VocationSerializer,分别对应模型PersonInfo和Vocation,模型序列化类的定义如下:

    from rest_framework import serializers
    from .models import PersonInfo, Vocation
    
    #定义ModelSerializer类
    class PersonInfoSerializer(serializers.ModelSerializer):
        class Meta:
            model = PersonInfo
            fields = '__all__'
    
    
    #定义ModeolSerializer类
    class VocationSerializer(serializers.ModelSerializer):
        name = PersonInfoSerializer()
        class Meta:
            model = Vocation
            fields = ('id', 'job', 'title', 'payment', 'name')
    
        def create(self, validated_data):
            #从validated_data中获取模型PersonInfo的数据
            name = validated_data.get('name', '')
            id = name.get('id', 0)
            p = PersonInfo.objects.filter(id=id).first()
            #根据id判断模型PersonInfo是否存在数据对象
            #若存在数据对象,则只对Vocation新增数据
            #若不存在,则先对模型PersonInfo新增数据
            #再对模型Vocation新增数据
            if not p:
                p = PersonInfo.objects.create(**name)
            data = validated_data
            data['name'] = p
            v = Vocation.objects.create(**data)
            return v
    
        def update(self, instance, validated_data):
            #从validated_data中获取模型PersonInfo的数据
            name = validated_data.get('name', '')
            id = name.get('id', 0)
            p = PersonInfo.objects.filter(id=id).first()
            #判断外键name是否存在模型PersonInfo
            if p:
                #若存在,则先更新模型PersonInfo的数据
                PersonInfo.objects.filter(id=id).update(**name)
                #再更新模型Vocation的数据
                data = validated_data
                data['name'] = p
                id = validated_data.get('id', '')
                v = Vocation.objects.filter(id=id).update(**data)
                return v
    index/serializers.py

      从上述代码看到,序列化类VocationSerializer对PersonInfoSerializer进行实例化并复制给变量name,而属性fields的name代表模型Vocation的外键字段name,同时也是变量name。换句话说,序列化字段name代表模型Vocation的外键字段name,而变量name作为序列化字段name的数据内容。

      变量name的名称必须与模型外键字段名称或者序列化字段名称一致,否则模型外键字段或者序列化字段无法匹配变量name,从而提示异常信息。

      序列化类VocationSerializer还重写了数据的新增函数create和修改函数update,因为不同数据关系的数据读写方式不相同,并且不同的开发需求可能导致数据读写方式有所不同。新增函数create和修改函数update的业务逻辑较为相似,业务逻辑说明如下:

        (1)从用户的请求参数(函数参数validated_data)获取模型PersonInfo的主键id,根据主键id查询模型PersonInfo是否已存在数据对象。

        (2)如果存在模型PersonInfo的数据对象,那么update函数首先修改模型PersonInfo的数据,然后修改模型Vocation的数据。

        (3)如果不存在模型PersonInfo的数据对象,那么create函数在模型PersonInfo的数据然后在模型Vocation中新增数据,确保模型Vocation的外键字段name不为空,使两个模型之间构成一对多的数据关系。

      下一步对视图函数vocationFef和视图类vocationClass的代码进行调整,代码的业务逻辑与1.3小结的相同,代码调整如下:

    from django.shortcuts import render
    from .models import PersonInfo, Vocation
    from .serializers import VocationSerializer
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from rest_framework.pagination import PageNumberPagination
    from rest_framework.decorators import api_view
    
    
    @api_view(['GET', 'POST'])
    def vocationDef(request):
        if request.method == 'GET':
            q = Vocation.objects.all().order_by('id')
            pg = PageNumberPagination()
            p = pg.paginate_queryset(queryset=q, request=request)
            serializer = VocationSerializer(instance=p, many=True)
            #返回对象Response由Django Rest Framework实现
            return Response(serializer.data)
        elif request.method == 'POST':
            #获取请求数据
            id = request.data.get('id', 0)
            #判断请求参数id在模型Vocation中是否存在
            #若存在,则执行数据修改;否则新增数据
            operation = Vocation.objects.filter(id=id).first()
            #数据验证
            serializer = VocationSerializer(data=request.data)
            if serializer.is_valid():
                if operation:
                    serializer.update(operation, request.data)
                else:
                    # 保存到数据库
                    serializer.save()
                # 返回对象Response由Django Rest Framework实现
                return Response(serializer.data)
            return Response(serializer.errors, status=404)
    
    class vocationClass(APIView):
        def get(self, request):
            q = Vocation.objects.all().order_by('id')
            #分页查询,需要在settings.py中设置REST_FRAMEWORK属性
            pg = PageNumberPagination()
            p = pg.paginate_queryset(queryset=q, request=request, view=self)
            serializer = VocationSerializer(instance=p, many=True)
            #返回对象Response由Django Rest Framework实现
            return Response(serializer.data)
    
        #POST请求
        def post(self, request):
            #获取请求数据
            id = request.data.get('id', 0)
            operation = Vocation.objects.filter(id=id).first()
            serializer = VocationSerializer(data=request.data)
            #数据验证
            if serializer.is_valid():
                if operation:
                    serializer.update(operation, request.data)
                else:
                    #保存到数据库
                    serializer.save()
                #返回对象Response由Django Rest Framework实现
                return Response(serializer.data)
            return Response(serializer.errors, status=404)
    index/views.py

      最后运行MyDjango,在浏览器上访问127.0.0.1:8000,模型Vocation的每行数据嵌套了模型PersonInfo的某行数据,两个模型的数据嵌套主要由模型Vocation的外键字段name实现关联

  • 相关阅读:
    实现两个整数变量的互换
    Js中replace替换所有*
    下载win10系统
    Linux网络基本网络配置方法介绍
    搭建Linux虚拟服务器
    解决SVN Cleanup错误: Failed to run the WC DB work queue associated with
    详细QRCode生成二维码和下载实现案例
    Win10中Vue.js的安装和项目搭建
    什么是Docker,它可干什么?
    Win10下搭建Git服务器
  • 原文地址:https://www.cnblogs.com/zhaop8078/p/12002698.html
Copyright © 2011-2022 走看看