现在,已经很少有单独一个应用系统就可以解决大多数问题的场景了。往往都是需要很多个,本地的或异地间的技术系统与应用,通过API实现功能上的集成或是数据上的交互。
Django REST framework 是一个强大且灵活的工具包,用以构建Rest Web APIs。可以让Django Web项目快速构建和交付出项目或模块的APIs服务能力。借助于这个工具,在简单的场景下,对于熟练使用者来说,为一个App模块赋能全面的API能力可能只是几分钟的事儿。
Django Rest Framework详细使用资料请参见官网 。
安装djangorestframework工具包
pip install djangorestframework
配置与开发步骤概要
大体上只需要以下4个步骤,就可以快速构建出一个Django项目App模块的API服务功能了:
- 在setting.py中添加Django Rest Framework功能,并对功能进行分页配置
- 在App中新建serializers.py文件,并定义Serializer类或ModelSerializer类
- 在urls.py中定义路由地址
- 在views.py中定义视图函数,三种定义方式分别为:
- 基于类的视图
- 基于函数的视图
- 重构ViewSets类(要求Python>=2.7, Django>=1.11),参见:https://www.django-rest-framework.org/tutorial/quickstart/
三种实现方法上的异同分析
- 基于函数的视图方法,要算是最简易的一种方法了,只需要在views.py中定义需要的api函数,引用api_view()装饰器,在urls.py中定义映射关系,即可完成。该方法用于解决一个项目模块局部的api使用需求时,会比较好。
- 基于类的视图方法,算是最为复杂的一种方法,相当于是一种支持API功能全定制的解决方案,需要在serializers.py中定义继承ModelSerializer类或者自定义继承Serializer的类,在views.py中定义继承APIView类的api工具类(在这个类里又可以按实际需求自定义需要支持的api 函数),在urls.py中定义映射关系。
- 基于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官网。
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')
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
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表中的数据:
基于函数的视图方法的示例
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下的模型类,定义了一张产品信息表
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
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')
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)
from django.urls import path
from . import views
urlpatterns = [
# 基于类的视图
path('', views.product_class.as_view()),
]
- 以上示例代码摘自玩转Django2.0一书第13章
注:setting.py的配置方法在三种实现方案中没有差别。