使用Django编写Restful API

在工作中写restful API是一个常见的事儿,用django来写restful API也是非常简单,先说明一下我的环境:
Django 2.1.8
Python 3.6.4
project的名称是naxx
APP的名称是naxxramas
MySQL 5.5.64-MariaDB

配置过程

首先,我们先去naxxramas/models.py里添加一个数据模型,比如:

1
2
3
4
5
6
# 记录各部门的监控覆盖率情况
class Monitor(models.Model):
domain_name = models.CharField(max_length=50) # 部门名
monitor_percentage = models.FloatField() # 监控覆盖率
def __str__(self):
return self.domain_name

保存退出后,我们往里面加一点数据,可以从Django自带的后台添加或者直接在MySQL里insert,如图:
akb48

pip install djangorestframework安装djangorestframework,然后在naxxramas文件夹里,新创建serializers.py文件,内容如下:

1
2
3
4
5
6
7
from .models import Monitor	#从同文件夹的models.py里引用Monitor类
from rest_framework import serializers

class MonitorSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Monitor
fields = ['domain_name', 'monitor_percentage'] #这个是需要展示的项,我这里把数据的所有列都写出来了,可以根据需要展示

然后编辑views.py,新增的内容如下:

1
2
3
4
5
6
7
默认内容略
from rest_framework import viewsets
from .serializers import MonitorSerializer

class MonitorViewSet(viewsets.ModelViewSet):
queryset = Monitor.objects.all() #这里会去读取Monitor数据模型里所有的值
serializer_class = GroupSerializer

最后一步,配置一下naxx/urls.py,这里我为了配置方便,把不同的APP放在对应的路径下统一管理了,如下:

1
2
3
4
5
6
7
8
9
from django.contrib import admin
from django.urls import path, include
from . import views

urlpatterns = [
path('admin/', admin.site.urls), #后台
path(r'naxx/', include('naxxramas.urls')), #naxx路径的单独去naxxramas里的urls.py里配置
path('', views.portal, name='portal'), #主页
]

再去编辑一下naxxramas/urls.py

1
2
3
4
5
6
7
8
9
10
11
from django.urls import path, include
from . import views
from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'monitor', views.MonitorViewSet)

urlpatterns = [
path('', include(router.urls)), #api相关
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), #api相关
]

还差最后一步,那就是去naxx/settngs.py里添加如下两个配置:

1
2
3
4
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}


1
2
3
4
INSTALLED_APPS = [
...
'rest_framework',
]

重启Django即可。

验证

要验证我们的api成功很简单,curl一下就行,这里我写了一个Python的脚本来使用requests验证,如下:

1
2
3
4
5
6
7
8
9
10
11
#python3,需要先pip install requests
#测试api的文件

import requests, json

monitorurl = 'http://127.0.0.1:8000/naxx/monitor/'

monitor_response = requests.get(monitorurl)
monitor_data_json = json.loads(monitor_response.text)

print('得到的monitor-json是:\n', monitor_data_json)

执行效果如下:
akb48

成功!

添加参数

上面的例子可见,我们请求的URL没有任何参数,而且数据库里有10多个数据,但是api取到的结果是默认是降序而且取的是前5位。那么如果我们要在url里添加参数怎么做?比如我们想要升序排列,而且这次只取三位。那么这次我们请求的URL路径是:http://127.0.0.1:8000/naxx/monitor/?order=top&num=3。

改一下views.py,如下:

1
2
3
4
5
6
7
8
9
10
11
12
class MonitorViewSet(viewsets.ModelViewSet):
#queryset = Monitor.objects.all()
serializer_class = MonitorSerializer
def get_queryset(self):
queryset = Monitor.objects.all()
num = self.request.query_params.get('num', '5') #这里判断是否得到num,如果没有默认为5
order = self.request.query_params.get('order', 'top') #这里判断是否得到order,如果没有认为是top
if num is not None and order == 'top':
queryset = queryset.order_by('-monitor_percentage')[0:int(num)] # 满足上面条件的话得到的是以monitor_percentage降序的前num位
elif num is not None and order == 'bottom':
queryset = queryset.order_by('monitor_percentage')[0:int(num)]
return queryset

保存之后,还要去修改naxxramas/urls.py,因为我们添加的参数,所以要在router.register添加对应的basename:

1
2
3

router.register(r'monitor', views.MonitorViewSet, basename='num' and 'order') #在原有的基础上添加了basename并且指定参数名是num和order

Django会默认重启,如果成功的话,再用上面的python脚本试试效果:
akb48

可见这次获取到了从小到大的三项数据了!

自定义JSON返回

如果此刻是按照做下来的话,会发现你的python脚本返回的值跟我不同。因为在实际工作中,每个公司都有自己的返回json格式,比如我们公司要求返回的格式是:

1
2
3
4
5
{
"success" : true,
"msg": "asdf",
"data": {}
}

而我已经修改了默认的返回格式,重新自定义JSONRenderer。自定义的方法简单说就是创建一个类去继承JSONRenderer,然后重构它的方法,然后在settings.py文件里修改默认使用的renderer类为我们自定义的类即可。

首先在naxx(也就是我的Django project)文件夹下创建一个utils文件夹,在这个文件夹里添加rendererresponse.py文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 导入控制返回的JSON格式的类
from rest_framework.renderers import JSONRenderer

class customrenderer(JSONRenderer):
# 重构render方法
def render(self, data, accepted_media_type=None, renderer_context=None):
if renderer_context:
# 获取需要返回的msg和code信息
if isinstance(data, dict):
msg = data.pop('msg', 'success')
code = data.pop('code', 0)
else:
msg = 'success'
code = 0
# 重新构建返回的JSON字典
ret = {
'success': True,
'msg': 'This Data from Alibaba-GOC',
'data': data,
}
# 返回JSON数据
return super().render(ret, accepted_media_type, renderer_context)
else:
return super().render(data, accepted_media_type, renderer_context)

保存退出后,在naxx/settings.py里我们刚刚添加的REST_FRAMEWORK字段改成这样:

1
2
3
4
5
6
7
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'DEFAULT_RENDERER_CLASSES': ( #添加这一部分
'utils.rendererresponse.customrenderer',
),
}

参考资料

https://www.django-rest-framework.org/tutorial/quickstart/
https://www.django-rest-framework.org/api-guide/viewsets/#viewset-actions
https://my.oschina.net/u/2474096/blog/1933456
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/
https://www.django-rest-framework.org/api-guide/filtering/
https://stackoverflow.com/questions/48299466/django-rest-framework-passing-parameters-with-get-request-classed-based-views

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------