1、安装环境
$ pip install django==1.11.5
$ pip install djangorestframework==3.6.4
创建应用
$ django-admin startproject restful01
$ cd restful01
$ python manage.py startapp toys
在setting.py中加入toys
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'toys.apps.ToysConfig',
]
app.py 中django.apps.AppConfig代表Django application和配置
调试工具
安装curl
安装postman
安装stoplight,用于多语言
安装iCurlHTTP,用于移动设备
2、创建数据模型、序列化和反序列化
toys/models.py中创建模型
class Toy(models.Model):
created = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=150, blank=False, default='')
description = models.CharField(max_length=2250, blank=True, default='')
toy_category = models.CharField(max_length=200, blank=False, default='')
release_date = models.DateTimeField()
was_included_in_home = models.BooleanField(default=False)
class Meta:
ordering = ('name', )
$ python manage.py makemigrations toys
$ python manage.py migrate
序列化toys/serializers.py
from rest_framework import serializers
from toys.models import Toy
class ToySerializer(serializers.Serializer):
pk = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=150)
description = serializers.CharField(max_length=250)
release_date = serializers.DateTimeField()
toy_category = serializers.CharField(max_length=200)
was_included_in_home = serializers.BooleanField(required=False)
def create(self, validated_data):
return Toy.objects.create(**validated_data) # create Toy model
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.release_date = validated_data.get('release_date', instance.release_date)
instance.toy_category = validated_data.get('toy_category', instance.toy_categoryv)
instance.was_included_in_home = validated_data.get('was_included_in_home', instance.was_included_in_home)
instance.save()
return instance
$ python manage.py shell 创建两个实例
from datetime import datetime
from django.utils import timezone
from django.utils.six import BytesIO
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from toys.models import Toy
from toys.serializers import ToySerializer
# 创建两个实例
toy_release_date = timezone.make_aware(datetime.now(),
timezone.get_current_timezone())
toy1 = Toy(name='Snoopy talking action figure',
description='Snoopy speaks five languages',
release_date=toy_release_date,
toy_category='Action figures',
was_included_in_home=False)
toy1.save()
toy2 = Toy(name='Hawaiian Barbie',
description='Barbie loves Hawaii',
release_date=toy_release_date, toy_category='Dolls',
was_included_in_home=True)
toy2.save()
print(toy1.pk)
print(toy1.name)
print(toy1.created)
print(toy1.was_included_in_home)
print(toy2.pk)
print(toy2.name)
print(toy2.created)
print(toy2.was_included_in_home)
序列化
serializer_for_toy1 = ToySerializer(toy1)
print(serializer_for_toy1.data)
serializer_for_toy2 = ToySerializer(toy2)
print(serializer_for_toy2.data)
将序列化数据封装成JSON
json_renderer = JSONRenderer()
toy1_rendered_into_json = json_renderer.render(serializer_for_toy1.data)
toy2_rendered_into_json = json_renderer.render(serializer_for_toy2.data)
print(toy1_rendered_into_json)
print(toy2_rendered_into_json)
反序列化过程,将JSON数据转换成Toy实例
json_string_for_new_toy = '{"name":"Clash Royale play set","description":"6 figures from Clash Royale", "release_date":"2017-10-09T12:10:00.776594Z","toy_category":"Playset","was_included_in_home":false}'
json_bytes_for_new_toy = bytes(json_string_for_new_toy, encoding="UTF-8")
stream_for_new_toy = BytesIO(json_bytes_for_new_toy)
parser = JSONParser()
parsed_new_toy = parser.parse(stream_for_new_toy)
print(parsed_new_toy)
new_toy_serializer = ToySerializer(data=parsed_new_toy)
if new_toy_serializer.is_valid():
toy3 = new_toy_serializer.save() # 保存数据库
print(toy3.name)
3、创建API视图
toys/views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from rest_framework import status
from toys.models import Toy
from toys.serializers import ToySerializer
class JSONResponse(HttpResponse):
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
@csrf_exempt
def toy_list(request):
if request.method == 'GET':
# 获取所有数据
toys = Toy.objects.all()
toys_serializer = ToySerializer(toys, many=True) # many表示多个实例
return JSONResponse(toys_serializer.data)
elif request.method == 'POST':
# 添加数据
toy_data = JSONParser().parse(request)
toys_serializer = ToySerializer(data=toy_data)
if toys_serializer.is_valid():
toys_serializer.save()
return JSONResponse(toys_serializer.data,
status=status.HTTP_201_CREATED)
return JSONResponse(toys_serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
@csrf_exempt
def toy_detail(request, pk):
try:
toy = Toy.objects.get(pk=pk)
except Toy.DoesNotExist:
return HttpResponse(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
toy_serializer = ToySerializer(toy)
return JSONResponse(toy_serializer.data)
elif request.method == 'PUT': # 更新数据
toy_data = JSONParser().parse(request)
toy_serializer = ToySerializer(toy, data=toy_data)
if toy_serializer.is_valid():
toy_serializer.save()
return JSONResponse(toy_serializer.data)
return JSONResponse(toy_serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
toy.delete()
return HttpResponse(status=status.HTTP_204_NO_CONTENT)
为视图函数创建路由URL
toys/urls.py
from django.conf.urls import url
from toys import views
urlpatterns = [
url(r'^toys/$', views.toy_list),
url(r'^toys/(?P<pk>[0-9]+$', views.toy_detail),
]
restful01/urls.py
from django.conf.urls import url, include
urlpatterns = [
url(r'^', include('toys.urls')),
]
启动服务 $ python manage.py runserver
使用postman去测试API
4、使用APIView类创建API
使用APIView能够减少不少代码
rest_framework.serializers.ModelSerializer默认实现create和update。
toys/serializers.py
from rest_framework import serializers
from toys.models import Toy
class ToySerializer(serializers.ModelSerializer):
class Meta:
model = Toy
fields = ('id',
'name',
'description',
'release_date',
'toy_category',
'was_included_in_home')
重新测试API
在views.py中函数中加入@api_view,处理异常
5、可浏览的API
rest_framework.response.BrowsableAPIRenderer提供text/html的返回内容。
默认使用Bootstrap库
6、使用高级的关系和序列化
将创建复制的API服务,能处理多张表,例如一个drone设备的数据模型
drone model, DroneCategory model, Pilot model, competition model。
scope | URI |
DroneCategory | /drone-categories/ |
DroneCategory | /drone-categories/{id} |
drones | /drone/ |
drones | /drone/{id} |
pilots | /pilots/ |
pilots | /pilots/{id} |
competitions | /competitions/ |
competitions | /competitions/{id} |
resources定义如下:
HTTP Verb | Scope | Semantics |
GET | DroneCategory | 获取所有记录 |
POST | DroneCategory | 创建一个新记录 |
PUT | DroneCategory | 更新一个已存在的记录 |
PATCH | DroneCategory | 更新多个字段 |
DELETE | DroneCategory | 删除一个记录 |
使用Django中的ORM(Object-Relational Mapping)功能。
$ python manage.py startapp drones
from django.db import models
class DroneCategory(models.Model):
name = models.CharField(max_length=250)
class Meta:
ordering = ('name', )
def __str__(self):
return self.name
class Drone(models.Model):
name = models.CharField(max_length=250)
drone_category = models.ForeignKey(
DroneCategory,
related_name='drones',
on_delete=models.CASCADE # 删除
)
manufacturing_date = models.DateTimeField()
has_it_competed = models.BooleanField(default=False)
inserted_timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('name', )
def __str__(self):
return self.name
class Pilot(models.Model):
MALE = 'M'
FEMALE = 'F'
GENDER_CHOICES = (
(MALE, 'Male'),
(FEMALE, 'Female'),
)
name = models.CharField(max_length=150, blank=False, default='')
gender = models.CharField(
max_length=2,
choices=GENDER_CHOICES,
default=MALE,
)
races_count = models.IntegerField()
inserted_timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('name', )
def __str__(self):
return self.name
class Competition(models.Model):
pilot = models.ForeignKey(
Pilot,
related_name='competitions',
on_delete=models.CASCADE
)
drone = models.ForeignKey(
Drone,
on_delete=models.CASCADE
)
distance_in_feet = models.IntegerField()
distance_achievement_date = models.DateTimeField()
class Meta:
ordering = ('-distance_in_feet', )
$ python manage.py makemigrations drones
$ python manage.py migrate
序列化drones/serializers.py
rest_framework.serializers.ModelSerializer
rest_framework.serializers.HyperlinkedModelSerializer
from rest_framework import serializers
from drones.models import DroneCategory
from drones.models import Drone
from drones.models import Pilot
from drones.models import Competition
import drones.views
class DroneCategorySerializer(serializers.HyperlinkedModelSerializer):
# one to many 关系
drones = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name='drone-detail'
)
class Meta:
model = DroneCategory
fields = ('url', 'pk', 'name', 'drones', )
class DroneSerializer(serializers.HyperlinkedModelSerializer):
# 代表关系唯一,显示类型名称
drone_category = serializers.SlugRelatedField(
queryset=DroneCategory.objects.all(),
slug_field='name')
class Meta:
model = Drone
fields = (
'url',
'name',
'drone_category',
'manufacturing_date',
'has_it_competed',
'inserted_timestamp'
)
class CompetitionSerializer(serializers.HyperlinkedModelSerializer):
drone = DroneSerializer()
class Meta:
model = Competition
fields = (
'url',
'pk',
'distance_in_feet',
'distance_achievement_date',
'drone'
)
class PilotSerializer(serializers.HyperlinkedModelSerializer):
competitions = CompetitionSerializer(
many=True,
read_only=True
)
gender = serializers.ChoiceField(choices=Pilot.GENDER_CHOICES)
gender_description = serializers.CharField(
source='get_gender_display',
read_only=True
)
class Meta:
model = Pilot
fields = (
'url',
'name',
'gender',
'gender_description',
'races_count',
'inserted_timestamp',
'competitions'
)
class PilotCompetitionSerializer(serializers.ModelSerializer):
pilot = serializers.SlugRelatedField(
queryset=Pilot.objects.all(),
slug_field='name'
)
drone = serializers.SlugRelatedField(
queryset=Drone.objects.all(),
slug_field='name'
)
class Meta:
model = Competition
fields = (
'url',
'pk',
'distance_in_feet',
'distance_achievement_date',
'pilot',
'drone'
)
使用基于类的视图 drones/views.py
from django.shortcuts import render
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.reverse import reverse
from drones.models import DroneCategory
from drones.models import Drone
from drones.models import Pilot
from drones.models import Competition
from drones.serializers import DroneCategorySerializer
from drones.serializers import DroneSerializer
from drones.serializers import PilotSerializer
from drones.serializers import PilotCompetitionSerializer
class DroneCategoryList(generics.ListCreateAPIView):
queryset = DroneCategory.objects.all()
serializer_class = DroneCategorySerializer
name = 'dronecategory-list'
class DroneCategoryDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = DroneCategory.objects.all()
serializer_class = DroneCategorySerializer
name = 'dronecategory-detail'
class DroneList(generics.ListCreateAPIView):
queryset = Drone.objects.all()
serializer_class = DroneSerializer
name = 'drone-list'
class DroneDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Drone.objects.all()
serializer_class = DroneSerializer
name = 'drone-detail'
class PilotList(generics.ListCreateAPIView):
queryset = Pilot.objects.all()
serializer_class = PilotSerializer
name = 'pilot-list'
class PilotDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Pilot.objects.all()
serializer_class = PilotSerializer
name = 'pilot-detail'
class CompetitionList(generics.ListCreateAPIView):
queryset = Competition.objects.all()
serializer_class = PilotCompetitionSerializer
name = 'competition-list'
class CompetitionDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Competition.objects.all()
serializer_class = PilotCompetitionSerializer
name = 'competition-detail'
# API
class ApiRoot(generics.GenericAPIView):
name = 'api-root'
def get(self, request, *args, **kwargs):
return Response({
'drone-categories': reverse(DroneCategoryList.name, request=request),
'drones': reverse(DroneList.name, request=request),
'pilots': reverse(PilotList.name, request=request),
'competitions': reverse(CompetitionList.name, request=request)
})
路由drones/urls.py 访问 http://127.0.0.1:8000/
from django.conf.urls import url
from drones import views
urlpatterns = [
url(r'^drone-categories/$',
views.DroneCategoryList.as_view(),
name=views.DroneCategoryList.name),
url(r'^drone-categories/(?P<pk>[0-9]+)$',
views.DroneCategoryDetail.as_view(),
name=views.DroneCategoryDetail.name),
url(r'^drones/$',
views.DroneList.as_view(),
name=views.DroneList.name),
url(r'^drones/(?P<pk>[0-9]+)$',
views.DroneDetail.as_view(),
name=views.DroneDetail.name),
url(r'^pilots/$',
views.PilotList.as_view(),
name=views.PilotList.name),
url(r'^pilots/(?P<pk>[0-9]+)$',
views.PilotDetail.as_view(),
name=views.PilotDetail.name),
url(r'^competitions/$',
views.CompetitionList.as_view(),
name=views.CompetitionList.name),
url(r'^competitions/(?P<pk>[0-9]+)$',
views.CompetitionDetail.as_view(),
name=views.CompetitionDetail.name),
url(r'^$',
views.ApiRoot.as_view(),
name=views.ApiRoot.name),
]
7、使用约束、过滤、搜索、排序和分页功能
防止重名
分页,
设置setting.py的方法
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 4
}
# curl -iX GET "localhost:8000/drones/?limit=4&offset=0
使用自定义的分页类的方法
通过改变全局配置rest_framework.pagination.LimitOffsetPagination类,这个类中的max_limit,默认为None,即无上限
drones/custompagination.py
from rest_framework.pagination import LimitOffsetPagination
class LimitOffsetPaginationWithUpperBound(LimitOffsetPagination):
max_limit = 8 # 最大页
setting.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'drones.custompagination.LimitOffsetPaginationWithUpperBound',
'PAGE_SIZE': 4
}
配置过滤、搜索等
前面的请求检索整个数据集,并且使用默认的排序。
$ pip install django-filter
将使用以下三个类:
- rest_framework.filters.OrderingFilter:允许控制排序
- django_filters.rest_framework.DjangoFilterBackend:允许开发者自定义类视图
- rest_framework.filters.SearchFilter:提供搜索功能
setting.py
INSTALLED_APPS = [
......
'django_filters',
]
......
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'drones.custompagination.LimitOffsetPaginationWithUpperBound',
'PAGE_SIZE': 4,
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.OrderingFilter',
'rest_framework.filters.SearchFilter',
),
}
在DroneCategoryList, DroneList, PilotList和CompetitionList中加入配置filter_fields, search_fields和ordering_fields。
drones/views.py
from rest_framework import filters
from django_filters import AllValuesFilter, DateTimeFilter, NumberFilter
class DroneCategoryList(generics.ListCreateAPIView):
queryset = DroneCategory.objects.all()
serializer_class = DroneCategorySerializer
name = 'dronecategory-list'
filter_fields = ('name', )
search_fields = ('^name', )
ordering_fields = ('name', )
class DroneList(generics.ListCreateAPIView):
queryset = Drone.objects.all()
serializer_class = DroneSerializer
name = 'drone-list'
filter_fields = ('name', 'drone_category',
'manufacturing_date', 'has_it_competed',)
search_fields = ('^name',)
ordering_fields = ('name','manufacturing_date', )
class PilotList(generics.ListCreateAPIView):
queryset = Pilot.objects.all()
serializer_class = PilotSerializer
name = 'pilot-list'
filter_fields = ('name', 'gender', 'races_count', )
search_fields = ('^name',)
ordering_fields = ('name', 'races_count',)
创建一个自定义的CompetitionFiler类
class CompetitionFilter(filters.FilterSet):
from_achievement_date = DateTimeFilter(
name='distance_achievement_date', lookup_expr='gte'
) # 大于等于某日期
to_achievement_date = DateTimeFilter(
name='distance_achievement_date', lookup_expr='lte'
)
min_distance_in_feet = NumberFilter(
name='distance_in_feet', lookup_expr='gte'
) # 大于等于某值
max_distance_in_feet = NumberFilter(
name='distance_in_feet', lookup_expr='lte'
)
drone_name = AllValuesFilter(
name='drone_name'
)
pilot_name = AllValuesFilter(
name='pilot_name'
)
class Meta:
model = Competition
fields = (
'distance_in_feet',
'from_achievement_date',
'to_achievement_date',
'min_distance_in_feet',
'max_distance_in_feet',
'drone_name',
'pilot_name',
)
class CompetitionList(generics.ListCreateAPIView):
queryset = Competition.objects.all()
serializer_class = PilotCompetitionSerializer
name = 'competition-list'
filter_class = CompetitionFilter
ordering_fields = (
'distance_in_feet',
'distance_achievement_date',
)
# http://localhost:8000/drone-categories/?name=copper
8、API权限
使用request对象的user和auth两个属性。
rest_framework提供了三个权限类,在rest_framework.authentication模块中。
- BasicAuthentication:提供了username和password的HTTP基本权限
- SessionAuthentication:用于Django的Session权限
- TokenAuthentication:提供一个简单的token权限,要求HTTP必须有'Token‘字段。
注,在生产环境下只提供https服务,所以不应该使用以上简单的http权限管理,我们可以使用一些第三方库
为了学习,我们使用BasicAuthentication
setting.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'drones.custompagination.LimitOffsetPaginationWithUpperBound',
'PAGE_SIZE': 4,
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.OrderingFilter',
'rest_framework.filters.SearchFilter',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
}
只有拥有权限的用户才能创建Drone,即PATCH,PUT和DELETE
request.user和request.auth确定请求是否准许。
在drones/models.py中增加owner字段,使用django.contrib.auth.User
class Drone(models.Model):
name = models.CharField(max_length=250, unique=True) # 唯一
drone_category = models.ForeignKey(
DroneCategory,
related_name='drones',
on_delete=models.CASCADE # 删除
)
manufacturing_date = models.DateTimeField()
has_it_competed = models.BooleanField(default=False)
inserted_timestamp = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(
'auth.User',
related_name='drones',
on_delete=models.CASCADE
)
class Meta:
ordering = ('name', )
def __str__(self):
return self.name
drones/serializers.py
from django.contrib.auth.models import User
class UserDroneSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Drone
fields = (
'url',
'name'
)
class UserSerializer(serializers.HyperlinkedModelSerializer):
drones = UserDroneSerializer(
many=True,
read_only=True
)
class Meta:
model = User
fields = (
'url',
'pk',
'username',
'drone'
)
class DroneSerializer(serializers.HyperlinkedModelSerializer):
# 代表关系唯一,显示类型名称
drone_category = serializers.SlugRelatedField(
queryset=DroneCategory.objects.all(),
slug_field='name')
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Drone
fields = (
'url',
'name',
'drone_category',
'owner',
'manufacturing_date',
'has_it_competed',
'inserted_timestamp'
)
自定义准许类,基于rest_framework.permissions.BasePermission
drones/custompermission.py
from rest_framework import permissions
class IsCurrentUserOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# 判断方法是否安全
if request.method in permissions.SAFE_METHODS:
return True
else:
return obj.owner == request.user
drones/views.py
from rest_framework import permissions
from drones import custompermission
......
class DroneList(generics.ListCreateAPIView):
queryset = Drone.objects.all()
serializer_class = DroneSerializer
name = 'drone-list'
filter_fields = ('name', 'drone_category',
'manufacturing_date', 'has_it_competed',)
search_fields = ('^name',)
ordering_fields = ('name','manufacturing_date', )
permission_classes = (
permissions.IsAuthenticatedOrReadOnly,
custompermission.IsCurrentUserOwnerOrReadOnly,
)
# 创建时调用
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class DroneDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Drone.objects.all()
serializer_class = DroneSerializer
name = 'drone-detail'
permission_classes = (
permissions.IsAuthenticatedOrReadOnly,
custompermission.IsCurrentUserOwnerOrReadOnly,
)
创建超级用户
$ python manage.py createsuperuser
username:copper , ps: ping2019
$ python manage.py makemigrations drones
选择1,输入默认owner为1,即id为1
$ python manage.py migrate
创建普通用户
$ python manage.py shell
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('user01', 'user01@example.com', 'user01password')
>>> user.save()
使用postman测试
urls.py
urlpatterns = [
url(r'^', include('toys.urls')),
url(r'^', include('drones.urls')),
url(r'^api-auth', include('rest_framework.urls')),
]
使用基于token的权限管理,用于Pilot数据表
setting.py
INSTALLED_APPS = [
......
'rest_framework.authtoken',
]
$ python manage.py migrate
drones/views.py
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication
class PilotList(generics.ListCreateAPIView):
queryset = Pilot.objects.all()
serializer_class = PilotSerializer
name = 'pilot-list'
filter_fields = ('name', 'gender', 'races_count', )
search_fields = ('^name',)
ordering_fields = ('name', 'races_count',)
authentication_classes = (
TokenAuthentication
)
permission_classes = (
IsAuthenticated
)
class PilotDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Pilot.objects.all()
serializer_class = PilotSerializer
name = 'pilot-detail'
authentication_classes = (
TokenAuthentication
)
permission_classes = (
IsAuthenticated
)
$ python manage.py shell
>>> from rest_framework.authtoken.models import Token
>>> from django.contrib.auth.models import User
>>> user = User.objects.get(username="user01")
>>> token = Token.objects.create(user=user)
>>> print(token.key)
9、使用限制规则和版本管理
限流,rest_framework提供了三个类,rest_framework.throttling --> SimpleRateThrottle --> BaseThrottle
setting.py
REST_FRAMEWORK = {
......
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'anon': '3/hour',
'user': '10/hour',
'drones': '20/hour',
'pilots': '15/hour',
}
}
配置视图views.py,有两个类
- throttle_classes:管理限制规则
- throttle_scope:累积请求数和限制请求率
from rest_framework.throttling import ScopedRateThrottle
class DroneDetail(generics.RetrieveUpdateDestroyAPIView):
throttle_scope = 'drones' # setting中drones的20/hour
throttle_classes = (ScopedRateThrottle, )
class DroneList(generics.ListCreateAPIView):
throttle_scope = 'drones'
throttle_classes = (ScopedRateThrottle, )
class PilotDetail(generics.RetrieveUpdateDestroyAPIView):
throttle_scope = 'pilots'
throttle_classes = (ScopedRateThrottle,)
class PilotList(generics.ListCreateAPIView):
throttle_scope = 'pilots'
throttle_classes = (ScopedRateThrottle,)
API版本v1、v2等
setting.py中添加
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning'
10、自动测试
$ pip install pytest