使用drf的Viewsets和Serializers可以大大简化视图和对数据进行增删该查的编写代码。本文将会通过一个示例项目,详细地介绍利用drf对数据进行操作。
示例代码github地址:
https://github.com/jinjidejuren/drf_learn
在对一个数据模型进行操作,一般的操作步骤如下:
1.确定models.py文件中模型的结构,也就是模型所包含的数据结构(该结构会映射到数据库中);
2.编写各模型对应的序列化类;
3.实现模型的视图操作类(在该类中可以实现搜索、分页、过滤、排序和权限控制等相关操作);
4.实现相关路由信息;
接下来我们逐个实现上述步骤,完成django rest framework开发的常见模式。而且在drf的官方文档中对各部分的实现也有详细的介绍。官方文档地址如下:
http://www.django-rest-framework.org/
django rest framework的使用要求如下:
REST framework requires the following:
Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
Django (1.10, 1.11, 2.0)
The following packages are optional:
coreapi (1.32.0+) - Schema generation support.
Markdown (2.1.0+) - Markdown support for the browsable API.
django-filter (1.0.1+) - Filtering support.
django-crispy-forms - Improved HTML display for filtering.
django-guardian (1.1.1+) - Object level permissions support.
python的版本最好是3.6.x, django 这里使用的是1.11版本,下边的其他组件,可以使用pip进行安装:
pip install coreapi Markdown django-filter django-crispy-forms django-guardian
在项目的配置文件settings/base.py中添加rest_framework到应用列表中:
INSTALLED_APPS = [
# 'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'apps.assets',
'apps.rbac'
]
自己的应用apps.assets也需要添加到应用列表中。
django rest framework的登录地址可以注册在主路由文件中,在conf/urls.py的urlpatterns中做如下设置:
url(r'^assets/v1/', include('apps.assets.urls')),
url(r'^api-auth/', include('rest_framework.urls')),
第一行我们对api接口的url设定版本为v1,这是为了符合restful接口标准(后续将会介绍restful接口设计标准,以及接口文档的编写)。
在apps/assets/models.py文件中定义各model模型,这个示例实现了Region(区域)、MachineRoom(机房)、Cabinet(机柜)、Device(设备):
from django.db import models
class Region(models.Model):
"""
区域
"""
region_name = models.CharField(verbose_name=u'区域', max_length=64, blank=True, unique=True)
created_time = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True, null=True)
modified_time = models.DateTimeField(verbose_name=u'修改时间', null=True)
is_delete = models.IntegerField(u'删除', default=0)
class Meta:
verbose_name = u'区域'
verbose_name_plural = verbose_name
def __str__(self):
return self.region_name
class MachineRoom(models.Model):
"""
机房
"""
room_name = models.CharField(verbose_name=u'机房名称', max_length=64, blank=True, unique=True)
room_code = models.CharField(verbose_name=u'机房编号', max_length=64, blank=True, null=True)
region_id = models.IntegerField(verbose_name=u'区域id', blank=True)
created_time = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True, null=True)
modified_time = models.DateTimeField(verbose_name=u'修改时间', null=True)
is_delete = models.IntegerField(u'删除', default=0)
class Meta:
verbose_name = u'机房'
verbose_name_plural = verbose_name
def __str__(self):
return self.room_name
class Cabinet(models.Model):
"""
机柜
"""
cabinet_name = models.CharField(verbose_name=u'机柜名称', max_length=64, blank=True)
cabinet_code = models.CharField(verbose_name=u'机柜编号', max_length=64, blank=True)
room_id = models.IntegerField(verbose_name=u'机房id', blank=True)
created_time = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True, null=True)
modified_time = models.DateTimeField(verbose_name=u'修改时间', null=True)
is_delete = models.IntegerField(u'删除', default=0)
class Meta:
verbose_name = u'机柜'
verbose_name_plural = verbose_name
def __str__(self):
return self.cabinet_name
class Device(models.Model):
"""
设备
"""
type_choices = (
('storage', '存储设备'),
('safe', '安全设备')
)
device_name = models.CharField(verbose_name=u'设备名称', max_length=64,
blank=True, unique=True)
device_type = models.CharField(verbose_name=u'设备类型', max_length=32,
choices=type_choices, blank=True)
brand = models.CharField(verbose_name=u'品牌', max_length=32, blank=True, null=True)
model = models.CharField(verbose_name=u'型号', max_length=32, blank=True, null=True)
hardware = models.TextField(verbose_name=u'硬件信息', blank=True, null=True)
cabinet_id = models.IntegerField(verbose_name=u'机柜id', blank=True)
created_time = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True, null=True)
modified_time = models.DateTimeField(verbose_name=u'修改时间', null=True)
is_delete = models.IntegerField(u'删除', default=0)
class Meta:
verbose_name = u'设备'
verbose_name_plural = verbose_name
def __str__(self):
return self.device_name
实现上述model的序列化类,写入serializers.py文件:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-23 下午10:36
# @Author : zhang chi
# @Site :
# @File : serializers.py
# @Software: PyCharm
from rest_framework import serializers
from .models import *
class RegionSerializer(serializers.ModelSerializer):
"""
区域序列化
"""
class Meta:
model = Region
fields = ('id', 'region_name', 'created_time', 'modified_time')
class MachineRoomSerializer(serializers.ModelSerializer):
"""
机房序列化
"""
class Meta:
model = MachineRoom
fields = ('id', 'room_name', 'room_code', 'region_id',
'created_time', 'modified_time')
class CabinetSerializer(serializers.ModelSerializer):
"""
机柜序列化
"""
class Meta:
model = Cabinet
fields = ('id', 'cabinet_name', 'cabinet_code', 'room_id',
'created_time', 'modified_time')
class DeviceSerializer(serializers.ModelSerializer):
"""
设备序列化
"""
class Meta:
model = Device
fields = ('id', 'device_name', 'device_type', 'brand', 'model',
'hardware', 'cabinet_id', 'created_time', 'modified_time')
class ServiceSerializer(serializers.ModelSerializer):
"""
服务器序列化
"""
class Meta:
model = Server
fields = ('id', 'project', 'manager', 'service_tag', 'server_status', 'server_name',
'environment', 'brand', 'model', 'assets_number', 'ip_addr', 'cabinet_id')
接着需要实现views.py中各model的视图,这里我们推荐继承ModelViewSet,ModelViewSet帮我们做了很多增、删、查、改的操作,简化了代码的编写,apps/assets/views.py实现如下:
from rest_framework import viewsets
from rest_framework import permissions
from .serializers import *
from .paginations import *
class RegionViewSet(viewsets.ModelViewSet):
"""
区域操作视图
"""
queryset = Region.objects.all()
serializer_class = RegionSerializer
pagination_class = MyFormatResultsSetPagination
permission_classes = (CustomerAccessPermission, )
class MachineRoomViewSet(viewsets.ModelViewSet):
"""
机房操作视图
"""
queryset = MachineRoom.objects.all()
serializer_class = MachineRoomSerializer
pagination_class = MyFormatResultsSetPagination
class CabinetViewSet(viewsets.ModelViewSet):
"""
机柜操作视图
"""
queryset = Cabinet.objects.all()
serializer_class = CabinetSerializer
pagination_class = MyFormatResultsSetPagination
class DeviceViewSet(viewsets.ModelViewSet):
"""
设备操作视图
"""
queryset = Device.objects.all()
serializer_class = DeviceSerializer
pagination_class = MyFormatResultsSetPagination
queryset、serializer_class、pagination_class分别对应ModelViewSet的返回集合、序列化类和分页类,如果有需求还可以设置排序方法、搜索、过滤的方法。这些类将会影响着返回的结果集合。所有操作的本质都是通过设置各种条件,将数据库中的数据按照指定的条件查询筛选出来。
上述视图最后都需要用户访问url获取,所以需要将路由添加到urls.py中,在conf/urls.py中,包含了assets的路由表。在apps/assets/urls.py中添加路由:
from django.conf.urls import url, include
from rest_framework import routers
from apps.assets import views
router = routers.DefaultRouter()
router.register(r'regions', views.RegionViewSet, base_name='regions')
router.register(r'machine_rooms', views.MachineRoomViewSet, base_name='machine_rooms')
router.register(r'cabinets', views.CabinetViewSet, base_name='cabinets')
router.register(r'devices', views.DeviceViewSet, base_name='devices')
urlpatterns = [
url(r'^', include(router.urls))
]
我在本机调试时开发的端口为8060,访问http://127.0.0.1:8060/assets/v1/页面内容如下:
访问regions内容:http://127.0.0.1:8060/assets/v1/regions/
可以在这个页面上进行新增操作,如果指定具体某个id的信息,可以进行编辑删除操作。例如访问id为1的regions:http://127.0.0.1:8060/assets/v1/regions/1/
作为一个drf入门的教程,我们可以了解到常见的开发模式。具体的细节和拓展在后续的课程进行讲解。例如过滤、排序、分页、搜索和权限控制。