`

利用 Django REST framework 编写 RESTful API

drf 
阅读更多

       

  • 自动生成符合 RESTful 规范的 API
    • 支持 OPTION、HEAD、POST、GET、PATCH、PUT、DELETE
    • 根据 Content-Type 来动态的返回数据类型(如 text、json)
  • 生成 browserable 的交互页面(自动为 API 生成非常友好的浏览器页面)
  • 非常细粒度的权限管理(可以细粒度到 field 级别)

示意图


安装

$ pip install djangorestframework
$ pip install markdown

概述

Django Rest framework 的流程大概是这样的

  1. 建立 Models
  2. 依靠 Serialiers 将数据库取出的数据 Parse 为 API 的数据(可用于返回给客户端,也可用于浏览器显示)
  3. ViewSet 是一个 views 的集合,根据客户端的请求(GET、POST等),返回 Serialiers 处理的数据
    • 权限 Premissions 也在这一步做处理
  4. ViewSet 可在 Routers 进行注册,注册后会显示在 Api Root 页上
  5. 在 urls 里注册 ViewSet 生成的 view,指定监听的 url

希望全面细致了解的人请移步去看官方文档,我这里就不一步步的细说了,而是分块来进行介绍


准备工作 & Models

让我们来写个小项目练练手

  1. 先用 manage.py startproject rest 来生成一个项目
  2. 再用 manage.py createsuperuser 创建用户(后面权限管理会用到)
  3. 初始化数据库 manage.py migrate

然后当然是编写 models,为了展示 rest_framework 的强大之处,我给 models 定义了一个自定义的 field

# myproject/myapp/models.py


#! /usr/bin/env python
# -*- coding: utf-8
from __future__ import unicode_literals, absolute_import
import cPickle as pickle

from django.db import models
from django.contrib.auth.models import User


class SerializedField(models.TextField):

    """序列化域
    用 pickle 来实现存储 Python 对象
    """
    __metaclass__ = models.SubfieldBase  # 必须指定该 metaclass 才能使用 to_python

    def validate(self, val):
        raise isinstance(val, basestring)

    def to_python(self, val):
        """从数据库中取出字符串,解析为 python 对象"""
        if val and isinstance(val, unicode):
            return pickle.loads(val.encode('utf-8'))

        return val

    def get_prep_value(self, val):
        """将 python object 存入数据库"""
        return pickle.dumps(val)


class MyModel(models.Model):

    created_at = models.DateTimeField(auto_now_add=True)
    # 注意这里建立了一个外键
    owner = models.ForeignKey(User, related_name='mymodels')
    field = models.CharField(max_length=100)
    options = SerializedField(max_length=1000, default={})

Serializers

定义好了 Models,我们可以开始写 Serializers,这个相当于 Django 的 Form

# myproject/myapp/serializers.py

#! /usr/bin/env python
# -*- coding: utf-8
from __future__ import unicode_literals, absolute_import
import json

from django.contrib.auth.models import User
from rest_framework import serializers

from ..models import MyModel
from .fields import MyCustField


class MyCustField(serializers.CharField):
    """为 Model 中的自定义域额外写的自定义 Serializer Field"""

    def to_representation(self, obj):
        """将从 Model 取出的数据 parse 给 Api"""
        return obj

    def to_internal_value(self, data):
        """将客户端传来的 json 数据 parse 给 Model"""
        return json.loads(data.encode('utf-8'))


class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User  # 定义关联的 Model
        fields = ('id', 'username', 'mymodels')  # 指定返回的 fields

    # 这句话的作用是为 MyModel 中的外键建立超链接,依赖于 urls 中的 name 参数
    # 不想要这个功能的话完全可以注释掉
    mymodels = serializers.HyperlinkedRelatedField(
        many=True, queryset=MyModel.objects.all(),
        view_name='model-detail'
    )


class MySerializer(serializers.ModelSerializer):

    options = MyCustField(
        max_length=1000, style={'base_template': 'textarea.html'},
    )

    class Meta:
        model = MyModel
        fields = ('id', 'owner', 'field', 'options')
        read_only_fields = ('owner',)  # 指定只读的 field

    def create(self, validated_data):
        """响应 POST 请求"""
        # 自动为用户提交的 model 添加 owner
        validated_data['owner'] = self.context['request'].user
        return MyModel.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """响应 PUT 请求"""
        instance.field = validated_data.get('field', instance.field)
        instance.save()
        return instance

ViewSet

定义好了 Serializers,就可以开始写 viewset 了

其实 viewset 反而是最简单的部分,rest_framework 原生提供了四种 ViewSet

  • ViewSet
  • GenericViewSet
    • 继承于 GenericAPIView
  • ModelViewSet
    • 自身提供了六种方法
    • list
    • create
    • retrieve
    • update
    • partial_update
    • destroy
  • ReadOnlyModelViewSet

我比较喜欢用 ModelViewSet,然后再用 Premissions 来管理权限

# myproject/myapp/views.py

#! /usr/bin/env python
# -*- coding: utf-8
from __future__ import unicode_literals, absolute_import

from django.contrib.auth.models import User
from rest_framework import permissions, viewsets, renderers
from rest_framework.decorators import (
    permission_classes, detail_route
)
from rest_framework.response import Response

from .serializers import MySerializer, UserSerializer
from .models import MyModel


class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    # 指定权限,下面马上讲到
    permission_classes = (permissions.IsAuthenticated,)


class ModelViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    @detail_route(renderer_classes=[renderers.StaticHTMLRenderer])
    def plaintext(self, request, *args, **kwargs):
        """自定义 Api 方法"""
        model = self.get_object()
        return Response(repr(model))

我在 ModelViewSet 中自定义了方法 plaintext,rest_framework 中对于自定义的 viewset 方法提供了两种装饰器

  • list_route
  • detail_route

区别就是 list_route 的参数不包含 pk(对应 list),而 detail_route 包含pk(对应 retrieve)

看一段代码就懂了

@list_route(methods=['post', 'delete'])
def custom_handler(self, request):
    pass


@detail_route(methods=['get'])
def custom_handler(self, request, pk=None):
    pass

Filters

前面根据 serializers 和 viewset 我们已经可以很好的提供数据接口和展示了。但是有时候我们需要通过 url参数 来对数据进行一些排序或过滤的操作,为此,rest-framwork 提供了 filters 来满足这一需求。

全局filter

可以在 settings 里指定应用到全局的 filter:

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',)
}

viewset 的 filter

也可以为 viewset 分别指定 filter,方法就是在定义 viewset 的时候定义一个名为filter_backend 的类变量:

class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer = UserSerializer
    filter_backends = (filters.DjangoFilterBackend,)

默认的 filter

rest-framework 提供了几个原生的 filter:

  • SearchFilter
filter_backends = (filters.SearchFilter,)
search_fields = ('username', 'email')  # 指定搜索的域

请求 http://example.com/api/users?search=russell

  • OrderingFilter
filter_backends = (filters.OrderingFilter,)
ordering_fields = ('username', 'email')

请求 http://example.com/api/users?ordering=account,-username

自定义 filter

自定义 filter 非常简单,只需要定义 filter_queryset(self, request, queryset, view) 方法,并返回一个 queryset 即可。

直接贴一个我写的例子:

class NodenameFilter(filters.BaseFilterBackend):

    """根据 nodename 来删选
      [nodename]: NeiWang
    """

    def filter_queryset(self, request, queryset, view):
        nodename = request.QUERY_PARAMS.get('nodename')
        if nodename:
            return queryset.filter(nodename=nodename)
        else:
            return queryset

如果参数匹配有误,想要抛出异常的话,也可以自定义 APIError,举个例子:

from rest_framework.exceptions import APIException


class FilterError(APIException):
    status_code = 406
    default_detail = 'Query arguments error!'

然后在 viewset 里直接抛出 raise FilterError 即可。


Premissions

顾名思义就是权限管理,用来给 ViewSet 设置权限,使用 premissions 可以方便的设置不同级别的权限:

  • 全局权限控制
  • ViewSet 的权限控制
  • Method 的权限
  • Object 的权限

被 premission 拦截的请求会有如下的返回结果:

  • 当用户已登录,但是被 premissions 限制,会返回 HTTP 403 Forbidden
  • 当用户未登录,被 premissions 限制会返回 HTTP 401 Unauthorized

默认的权限

rest_framework 中提供了七种权限

  • AllowAny # 无限制
  • IsAuthenticated # 登陆用户
  • IsAdminUser # Admin 用户
  • IsAuthenticatedOrReadOnly # 非登录用户只读
  • DjangoModelPermissions # 以下都是根据 Django 的 ModelPremissions
  • DjangoModelPermissionsOrAnonReadOnly
  • DjangoObjectPermissions

全局权限控制

在 settings.py 中可以设置全局默认权限

# settings.py

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.AllowAny',
    ),
}

ViewSet 的权限

可以设置 permission_classes 的类属性来给 viewset 设定权限,restframework 会检查元组内的每一个 premission,必须要全部通过才行。

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    # 设置权限,是一个元组
    permission_classes = (permissions.IsAuthenticated,)

自定义权限

Premissions 可以非常方便的定制,比如我就自己写了一个只允许 owner 编辑的权限

# myproject/myapp/premissions.py

#! /usr/bin/env python
# -*- coding: utf-8
from __future__ import unicode_literals, absolute_import

from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):

    def has_permission(self, request, view):
        """针对每一次请求的权限检查"""
        if request.method in permissions.SAFE_METHODS:
            return True

    def has_object_permission(self, request, view, obj):
        """针对数据库条目的权限检查,返回 True 表示允许"""
        # 允许访问只读方法
        if request.method in permissions.SAFE_METHODS:
            return True

        # 非安全方法需要检查用户是否是 owner
        return obj.owner == request.user

urls & routers

# myproject/myapp/urls.py

#! /usr/bin/env python
# -*- coding: utf-8
from __future__ import unicode_literals, absolute_import

from django.conf.urls import url, patterns, include
from rest_framework.routers import DefaultRouter

from . import views


# as_view 方法生成 view
# 可以非常方便的指定 `{Http Method: View Method}`
user_detail = views.UserViewSet.as_view({'get': 'retrieve'})
user_list = views.UserViewSet.as_view({'get': 'list', 'post': 'create'})

# plaintext 是我的自定义方法,也可以非常方便的指定
modal_plain = views.ModelViewSet.as_view({'get': 'plaintext'})
model_detail = views.ModelViewSet.as_view({'get': 'retrieve', 'post': 'create'})
model_list = views.ModelViewSet.as_view({'get': 'list', 'post': 'create'})

# router 的作用就是自动生成 Api Root 页面
router = DefaultRouter()
router.register(r'models', views.ModelViewSet)
router.register(r'users', views.UserViewSet)


# 不要忘了把 views 注册到 urls 中
urlpatterns = patterns(
    '',
    url(r'^', include(router.urls)),  # Api Root
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^models/(?P<pk>[0-9]+)/$', model_detail, name='model-detail'),
    url(r'^models/(?P<pk>[0-9]+)/plain/$', modal_plain, name='model-plain'),
    url(r'^models/$', model_list, name='model-list'),
    url(r'^users/$', user_list, name='user-list'),
    url(r'^users/(?P<pk>[0-9]+)/$', user_detail, name='user-detail'),
)

时间仓促,就介绍这些,以后有空再介绍一下在 Django 用 JWT 作为身份凭证。下面是一些效果图

  • Api Root

  • Users

分享到:
评论

相关推荐

    基于Django和Django Rest Framework的RESTful API前后端分离设计源码

    该项目为基于Django和Django Rest Framework实现的RESTful API前后端分离设计源码,共计77个文件,涵盖36个Python源文件、26个XML文件、7个HTML文件、4个Idea项目文件、1个Git忽略文件、1个许可证文件、1个Markdown...

    Django REST framework讲义PDF全集,中文文档PDF版

    Django REST Framework提供了一系列工具和库,简化了开发RESTful API的过程。它包括序列化、认证、权限管理、分页、过滤等关键功能,并且支持自定义,以满足各种项目需求。DRF的API友好,文档详尽,社区活跃,是开发...

    django rest framework开发生鲜电商

    总结起来,"django rest framework开发生鲜电商"这个项目是利用Django REST framework强大的API构建能力,结合Vue.js的前端优势,来打造一个高效、用户友好的生鲜电商系统。通过理解并掌握这两个技术,开发者能够...

    Django REST framework 中文文档.pdf

    整体上,Django REST framework中文文档是为希望学习或了解如何使用DRF构建RESTful API的开发者提供的宝贵资源。文档详细介绍了DRF的核心组件和高级特性,通过这些知识点,开发者可以快速搭建起符合RESTful架构风格...

    Django-REST-framework教程中文版

    本教程基于Django1.9以及restframework-v3.3.3版本,着重介绍了序列化、请求和响应处理、类视图、认证和权限、关联关系及超链接处理以及ViewSets和Routers的使用。 首先,在快速入门章节中,教程引导我们如何搭建一...

    详解Django rest_framework实现RESTful API

    Django rest_framework是Python的一种后端框架,它非常适合用来构建RESTful API。RESTful API是一种网络API设计风格和开发方式,它基于REST架构风格实现。REST代表"Representational State Transfer",中文可以译为...

    基于django restframework.zip

    【标题】:基于Django REST framework的...总结:这个项目展示了如何利用Django REST framework构建高效、安全的Web API,涉及到了多个核心概念和技术,对于理解RESTful API开发和Django框架的使用具有很高的学习价值。

    Django restframework课件笔记详解

    Django REST framework(简称DRF)是Python Web开发领域中一个强大的工具,专门用于构建Web API。这个框架基于Django,提供了许多高级特性,使得开发者能够高效、灵活地构建高质量的RESTful API服务。本课件笔记将...

    基于Django Rest Framework开发的API服务,为天堂山信息管理系统的移动端服务 .zip

    这个项目是利用Django Rest Framework构建的API服务,主要用于天堂山信息管理系统的移动端应用。通过GitHub托管,开发者可以获取到源代码并参与到项目中。项目结构遵循Django的惯例,包含必要的配置、应用代码、路由...

    Django rest framework中文

    Django REST framework(DRF)是一个强大的、灵活且易于使用的工具,旨在简化在Django项目中创建RESTful Web API的过程。接下来,我将详细介绍从零开始搭建一个Django REST framework中文教程所涉及的关键知识点。 ...

    django3.0+rest framework + Vue 生鲜超市项目-后端

    在本项目中,我们探索的是一个基于Django 3.0、Django Rest Framework和Vue.js构建的生鲜超市电子商务平台的后端实现。这个项目旨在提供一个完整的开发环境,供学习者深入理解如何将这些技术整合在一起,创建一个...

    django-rest-framework 官方文档

    总之,Django REST Framework是构建高质量、可维护的RESTful API的理想选择。通过深入学习和实践其官方文档,开发者可以掌握构建Web API的全部流程,从而提升开发效率和API质量。在实际工作中,不断交流和分享经验,...

    Python Django Web典型模块开发实战_用Django REST framework实现豆瓣API应用项目.pdf

    **Django REST framework** - Django REST framework(简称DRF)是Django的一个强大扩展,专门用于构建RESTful API。它提供了一系列工具和功能,使得构建Web API变得简单,包括序列化、认证、权限管理、分页和过滤等...

    django rest framework

    Django REST Framework(简称DRF)是基于Python的Django Web框架构建RESTful API的强大工具。它提供了一套完整的解决方案,包括序列化、身份验证、权限控制、分页以及Web视图,使得开发高质量、可维护的API变得更加...

    基于Django框架,使用Django REST framework前后端分离技术搭建的网上图书商店.zip

    Django REST framework是Django的一个扩展库,专门用于构建RESTful API。它提供了丰富的功能,如序列化、认证、权限控制、分页、过滤等,使开发REST API变得更加简单。本项目中,Django REST framework被用来设计和...

    Python库 | django-rest-framework-social-oauth2-1.0.1.tar.gz

    Django Rest Framework(简称DRF)是 Django 生态系统中的一个强大工具,专门用于构建 RESTful API。它提供了一系列强大的功能,如序列化、认证、权限管理、分页和过滤等。通过 DRF,开发者可以更高效地构建可读性高...

    基于Django Restframework的异常检测系统.zip

    Django是Python Web开发的一个强大框架,而Django Restframework则是Django上的一个高级API开发工具,它简化了RESTful API的构建过程。 1. Django框架: - Django遵循MVT(Model-View-Template)架构模式,用于...

    Django-Rest-Framework 学生信息查询 RESTFul API 实现代码

    在本文中,我们将深入探讨如何使用Django Rest Framework(DRF)构建一个学生信息查询的RESTful API。RESTful API是一种遵循REST(Representational State Transfer)架构风格的Web服务设计,允许客户端和服务器之间...

    channels-api:具有Django Rest Framework和Channels的RESTful Websocket API

    综上所述,这个项目或教程将指导开发者如何利用Django Rest Framework构建RESTful API,并结合Django Channels实现实时Websocket通信,从而创建一个综合性的Web应用程序。学习者可以从中学到如何在Python和Django...

    基于Django Restframework的异常检测系统,分析服务为Spark SQL和Spark Mllib.zip

    【标题】中的“基于Django Restframework的异常检测系统,分析服务为Spark SQL和Spark Mllib.zip”指的是一项利用Django Restframework构建的异常检测系统,该系统依赖于Apache Spark的SQL模块和Mllib机器学习库进行...

Global site tag (gtag.js) - Google Analytics