使用Django Rest Framework API工具为Django Web项目快速实现API服务的三种方法

现在,已经很少有单独一个应用系统就可以解决大多数问题的场景了。往往都是需要很多个,本地的或异地间的技术系统与应用,通过API实现功能上的集成或是数据上的交互。
Django REST framework 是一个强大且灵活的工具包,用以构建Rest Web APIs。可以让Django Web项目快速构建和交付出项目或模块的APIs服务能力。借助于这个工具,在简单的场景下,对于熟练使用者来说,为一个App模块赋能全面的API能力可能只是几分钟的事儿。
Django Rest Framework详细使用资料请参见官网

安装djangorestframework工具包

pip install djangorestframework

配置与开发步骤概要

大体上只需要以下4个步骤,就可以快速构建出一个Django项目App模块的API服务功能了:

  1. 在setting.py中添加Django Rest Framework功能,并对功能进行分页配置
  2. 在App中新建serializers.py文件,并定义Serializer类或ModelSerializer类
  3. 在urls.py中定义路由地址
  4. 在views.py中定义视图函数,三种定义方式分别为:

三种实现方法上的异同分析

  1. 基于函数的视图方法,要算是最简易的一种方法了,只需要在views.py中定义需要的api函数,引用api_view()装饰器,在urls.py中定义映射关系,即可完成。该方法用于解决一个项目模块局部的api使用需求时,会比较好。
  2. 基于类的视图方法,算是最为复杂的一种方法,相当于是一种支持API功能全定制的解决方案,需要在serializers.py中定义继承ModelSerializer类或者自定义继承Serializer的类,在views.py中定义继承APIView类的api工具类(在这个类里又可以按实际需求自定义需要支持的api 函数),在urls.py中定义映射关系。
  3. 基于ViewSets类的方法,是比较推荐的一种方法,它适合为项目模块增加全局性的API功能支持,同时因为它已经帮你把GET/POST相关操作全部做了封装实现,所以你自己只需要是在模块app的目录下serializers.py和views.py,urls.py文件中增加一些必要的配置内容即可。这会是一个功能全面的API,无论你是否需要那么多。

基于ViewSets类的使用方法示例

以下是为Django默认提供的auth模块提供的User, Group两个表的API功能实现,Django项目名是tutorial,App应用名为quickstart。
示例摘自django-ret-framework官网。

serializers.py

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

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups')

class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')

views.py

from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from tutorial.quickstart.serializers import UserSerializer, GroupSerializer

class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer


class GroupViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

urls.py

from django.urls import include, path
from rest_framework import routers
from tutorial.quickstart import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)

# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
    path('', include(router.urls)),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

settings.py 为api增加分页功能

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}

settings.py 将API模块添加到项目的apps中

INSTALLED_APPS = (
    ...
    'rest_framework',
)

测试下api接口的效果

在命令行中:

curl -H 'Accept: application/json; indent=4' -u admin:password123 http://127.0.0.1:8000/users/

或者直接在浏览器中访问:http://127.0.0.1:8000/users/

以下截图是在一个实验环境中做的模拟,使用的是项目名djangosite, App名称search的例子:
在这里插入图片描述
查看API提供了哪些可查询的资源:
在这里插入图片描述
查询User表中的数据:
在这里插入图片描述

基于函数的视图方法的示例

views.py

from .models import Product
from .serializers import ProductSerializer,MySerializer

# 普通函数方式生成视图
from rest_framework.decorators import api_view
@api_view(['GET', 'POST'])
def product_def(request, pk):
    if request.method == 'GET':
        queryset = Product.objects.filter(id=pk).all()
        serializer = ProductSerializer(instance=queryset, many=True)
        # 返回对象Response由Django Rest Framework实现
        return Response(serializer.data)
    elif request.method == 'POST':
        # 获取请求数据
        serializer = ProductSerializer(data=request.data)
        # 数据验证
        if serializer.is_valid():
            # 保存到数据库
            serializer.save()
            # 返回对象Response由Django Rest Framework实现,status是设置响应状态码
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  • 以上示例代码摘自玩转Django2.0一书第13章,其中Product是一个App下的模型类,定义了一张产品信息表

urls.py

from django.urls import path
from . import views
urlpatterns = [
    # 基于函数的视图
    path('<int:pk>', views.product_def),
]

注:setting.py的配置方法在三种实现方案中没有差别。

基于类的视图方法的示例

models.py
看下用到的两个模型类

from django.db import models
# 产品分类表
class Type(models.Model):
    id = models.AutoField('序号', primary_key=True)
    type_name = models.CharField('产品类型', max_length=20)
    # 设置返回值
    def __str__(self):
        return self.type_name

# 产品信息表
class Product(models.Model):
    id = models.AutoField('序号', primary_key=True)
    name = models.CharField('名称',max_length=50)
    weight = models.CharField('重量',max_length=20)
    size = models.CharField('尺寸',max_length=20)
    type = models.ForeignKey(Type, on_delete=models.CASCADE,verbose_name='产品类型')
    # 设置返回值
    def __str__(self):
        return self.name

serializers.py

from rest_framework import serializers
from .models import Product, Type
# 定义Serializer类
# 设置下拉内容
# 模型Type的__str__函数返回什么字段,type_name就要查询对应的字段
type_name = Type.objects.values('type_name').all()
TYPE_CHOICES = [item['type_name'] for item in type_name]

# 方法一,继承Serializer类,重写函数方法
class MySerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(required=True, allow_blank=False, max_length=100)
    weight = serializers.CharField(required=True, allow_blank=False, max_length=100)
    size = serializers.CharField(required=True, allow_blank=False, max_length=100)
    type = serializers.ChoiceField(choices=TYPE_CHOICES, default=1)
    # 如果使用MySerializer加载模型Product
    # 也可以改用PrimaryKeyRelatedField指定模型Type的外键
    # type = serializers.PrimaryKeyRelatedField(queryset=type_name, required=True)

    # 重写create函数,将API数据保存到数据表index_product
    def create(self, validated_data):
        return Product.objects.create(**validated_data)

    # 重写update函数,将API数据更新到数据表index_product
    def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.weight = validated_data.get('weight', instance.weight)
        instance.size = validated_data.get('size', instance.size)
        instance.type = validated_data.get('type', instance.type)
        instance.save()
        return instance

# 方法二,继续ModelSerializer类
class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'
        # fields = ('id', 'name', 'weight', 'size', 'type')

views.py

from .models import Product
from .serializers import ProductSerializer,MySerializer

# APIView 方式生成视图
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.pagination import PageNumberPagination
class product_class(APIView):
    # get 请求
    def get(self, request):
        queryset = Product.objects.all()
        # 分页查询,需要在settings.py设置REST_FRAMEWORK属性
        pg = PageNumberPagination()
        page_roles = pg.paginate_queryset(queryset=queryset, request=request, view=self)
        serializer = ProductSerializer(instance=page_roles, many=True)
        # serializer = ProductSerializer(instance=queryset, many=True) # 全表查询
        # 还可以使用MySerializer加载模型Product
        # serializer = MySerializer(instance=page_roles, many=True)
        # 返回对象Response由Django Rest Framework实现
        return Response(serializer.data)
    # post 请求
    def post(self, request):
        # 获取请求数据
        serializer = ProductSerializer(data=request.data)
        # 数据验证
        if serializer.is_valid():
            # 保存到数据库
            serializer.save()
            # 返回对象Response由Django Rest Framework实现,status是设置响应状态码
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

urls.py

from django.urls import path
from . import views
urlpatterns = [
    # 基于类的视图
    path('', views.product_class.as_view()),
]
  • 以上示例代码摘自玩转Django2.0一书第13章

注:setting.py的配置方法在三种实现方案中没有差别。

猜你喜欢

转载自blog.csdn.net/watermelonbig/article/details/88865974