美文网首页
教你 10 分钟构建一套 RESTful API 服务( Dja

教你 10 分钟构建一套 RESTful API 服务( Dja

作者: AirPython | 来源:发表于2020-06-29 22:09 被阅读0次
    image

    1. 前言

    前面用了两篇文章,分别用 Java + Spring Boot 和 Python + Flask 在本地构建了一套 RESTful API 服务

    本篇原计划是在上篇文章的基础上,聊聊 flask_restplus 和 Restless 依赖插件的增强使用场景的

    但是,有些小伙伴希望我能写一下 Django 实现 RESTful API 的实现过程

    因此本篇将介绍 Django 搭建 RESTful API 的流程 ,使用的技术栈是:Django + djangorestframework + django-rest-swagger

    2. 安装依赖

    使用 Django 编写 RESTful API 之前,我们需要先在虚拟环境内安装对应的依赖​ 具体包含:

    • Django:基础 Web 框架

    • djangorestframework:Django 的扩展,增加了对快速构建 REST API 的支持

    • django-rest-swagger:Django 支持的Swagger UI,可以生成 API 接口文档

    • django-filter:配合 djangorestframework 完成数据过滤需求

    # 安装依赖
    pip3 install Django
    
    pip3 install djangorestframework
    
    # API 可视化
    pip3 install django-rest-swagger
    
    # 配合djangorestframework使用,过滤数据( 可选 )
    pip3 install django-filter
    

    3. 准备

    首先,我们使用 Pycharm 创建一个 Django 项目,并新增一个 App

    image

    为了简化过程,使用命令行连接本地 Mysql 数据库 ,并新建一个名为 rest 的数据库

    然后,在项目的设置文件 settings.py 中,指定默认的数据库连接信息

    # api/api/settings.py
    DATABASES = {
    
        # 默认:Mysql数据库中的rest
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'rest',
            'USER': 'root',
            'PASSWORD': 'root',
            'HOST': 'localhost',
            'PORT': '3306',
        },
        'sqlite3': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
    

    为了兼容 Django 旧版本,在项目根目录新建一个 init.py 文件,并指定以 PyMysql 连接数据库

    # api/__init__.py
    import pymysql
    pymysql.install_as_MySQLdb()
    

    接着,编辑 settings.py 文件

    针对 djangorestframework,配置 App 及异常、权限、可视化、解析方式等内容

    # api/api/settings.py
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'rest_framework',
        'django_filters',
        'restfulapi',
        'rest_framework_swagger',
    ]
    
    # drf 配置,包含:异常、权限
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
        ],
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework.renderers.JSONRenderer',
        ),
        # 解析
        'DEFAULT_PARSER_CLASSES': (
            'rest_framework.parsers.JSONParser',
        ),
        # API 可视化
        'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
        # 异常
        'EXCEPTION_HANDLER': 'utils.custom_execption.custom_exception_handler',
    }
    

    4. 实现

    具体步骤如下:

    第 1 步,编写模型,并映射数据库

    新建一个类,继承自 django.db.models 中的 Model 对象,新增几个字段,指定数据类型和默认值

    # api/restfulapi/models.py
    from django.db import models
    
    class Music(models.Model):
        song = models.CharField(max_length=100,default='')
        singer = models.CharField(max_length=100,default='')
        created = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            db_table = 'music'
    

    然后,使用下面 2 条命令,将模型映射到数据,生成一张 music 表

    # 映射到数据库
    # 创建
    python3 manage.py makemigrations  --empty  restfulapi
    
    # 映射迁移
    python3 manage.py migrate
    
    image

    第 2 步,序列化模型

    使用 djangorestframework 提供的序列化器 ModelSerializer,将上面定义好的模型转换为其他数据格式,比如:JSON

    需要注意的是,这里可以序列化所有字段,也可能只序列化一部分字段

    # api/restfulapi/serializers.py
    from rest_framework import serializers
    from .models import Music
    
    # 序列化模型为其他格式
    
    class MusicSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = Music
    
            # 序列化所有的字段
            fields = '__all__'
    
            # 序列化部分字段
            # fields = ('id','song','singer','last_modify_date','created')
    

    第 3 步,定义 CRUD

    djangorestframework 的 ModelViewSet 定义了 CRUD 的全部功能

    所以只需要编写一个 ModelViewSet 的子类,重写 create()、list()、retrieve()、update()、destory() 方法即可

    当然,这里也可以使用 django_filters 来过滤数据,来完成一些复杂的查询场景

    # api/restfulapi/views.py
    from rest_framework import viewsets
    
    class MusicViewSet(viewsets.ModelViewSet):
        """
        CRUD 功能
        """
        authentication_classes = []
        permission_classes = []
    
        # 解析方式
        parser_classes = (MultiPartParser, FormParser, JSONParser)
    
        queryset = Music.objects.all()
        serializer_class = MusicSerializer
    
        def create(self, request, *args, **kwargs):
            """新建一条音乐"""
            pass
    
        def list(self, request, *args, **kwargs):
            """全部音乐数据"""
            pass
    
        def retrieve(self, request, *args, **kwargs):
            """查询一条数据"""
            pass
    
        def update(self, request, *args, **kwargs):
            """更新一条音乐数据"""
            pass
    
        def destroy(self, request, *args, **kwargs):
            """删除一条数据"""
            pass
    

    第 4 步,返回数据统一化并异常处理

    为了保证返回的数据结构一致,自定义 Response 和 ModelViewSet 的子类,将上面的 CRUD 进行一次封装

    class JsonResponse(Response):
        """
        自定义Response,继承rest framework的Response
        """
    
        def __init__(self, data=None, code=None, msg=None,
                     status=None,
                     template_name=None, headers=None,
                     exception=False, content_type=None):
            """
            Alters the init arguments slightly.
            For example, drop 'template_name', and instead use 'data'.
            Setting 'renderer' and 'media_type' will typically be deferred,
            For example being set automatically by the `APIView`.
            """
            super(Response, self).__init__(None, status=status)
    
            if isinstance(data, Serializer):
                msg = (
                    'You passed a Serializer instance as data, but '
                    'probably meant to pass serialized `.data` or '
                    '`.error`. representation.'
                )
                raise AssertionError(msg)
    
            self.data = {"code": code, "message": msg, "data": data}
            self.template_name = template_name
            self.exception = exception
            self.content_type = content_type
    
            if headers:
                for name, value in six.iteritems(headers):
    

    异常处理:针对不存在的资源请求,不同的错误状态码,返回不同的数据

    需要注意的是, settings.py 文件指定的异常处理类和该异常处理类的路径要保持一致

    # 异常处理
    def custom_exception_handler(exc, context):
        # Call REST framework's default exception handler first,
        # to get the standard error response.
        response = exception_handler(exc, context)
    
        # Now add the HTTP status code to the response.
        if response is not None:
            print(response.data)
            response.data.clear()
            response.data['code'] = response.status_code
            response.data['data'] = []
    
            if response.status_code == 404:
                try:
                    response.data['message'] = response.data.pop('detail')
                    response.data['message'] = "Not found"
                except KeyError:
                    response.data['message'] = "Not found"
    
            if response.status_code == 400:
                response.data['message'] = 'Input error'
    
            elif response.status_code == 401:
                response.data['message'] = "Auth failed"
    
            elif response.status_code >= 500:
                response.data['message'] = "Internal service errors"
    
            elif response.status_code == 403:
                response.data['message'] = "Access denied"
    
            elif response.status_code == 405:
                response.data['message'] = 'Request method error'
        return response
    

    第 5 步,定义路由

    在项目的 url.py 文件中,使用 DRF 中 DefaultRouter 实例对象注册,并定义路由地址

    # api/api/urls.py
    from django.urls import path, include
    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    router.register(r'music', views.MusicViewSet)
    
    urlpatterns = [
        path('admin/', admin.site.urls),
    
        path(r'v1.0/', include(router.urls)),
    ]
    

    第 6 步,可视化

    编辑第 5 步的文件,使用 rest_framework_swagger 中的 get_swagger_view() 函数,创建一个可视化的 API 界面

    # api/api/urls.py
    from rest_framework_swagger.views import get_swagger_view
    
    schema_view = get_swagger_view(title='API服务')
    ​
    urlpatterns = [
        url(r'^$', schema_view),
    ]
    

    最后,运行项目,访问下面的链接,即可以看到定义好的 RESTful API 服务了

    http://127.0.0.1:8000/

    image

    5. 最后

    上面就是通过 Django +djangorestframework实现 RESTful API 完整的流程了

    我已经将文中全部源码上传到公众号后台,关注公众号「 AirPython 」后回复「 rest3 」即可获得全部源码

    如果你觉得文章还不错,请大家点赞分享下。你的肯定是我最大的鼓励和支持。

    推荐阅读

    教你 10 分钟构建一套 RESTful API 服务-上

    教你 10 分钟构建一套 RESTful API 服务-中

    行为驱动开发:一篇文章带你用 Python 玩转 BDD

    相关文章

      网友评论

          本文标题:教你 10 分钟构建一套 RESTful API 服务( Dja

          本文链接:https://www.haomeiwen.com/subject/yqxzfktx.html