参考:
https://www.cnblogs.com/xiaonq/p/10053234.html
http://www.cnblogs.com/wupeiqi/articles/7805382.html
什么是restful
1. REST与技术无关,代表的是一种软件架构风格(REST是Representational State Transfer的简称,中文翻译为“表征状态转移”)
2. REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识
3. 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
4. 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
restful规范设计
1、API与用户的通信协议,总是使用HTTPs协议。
2、域名
1)子域名方式
https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
https://www.example.com
2)url方式
https://example.org
https://example.org/api/ API很简单
3、版本
URL,如:https://api.example.com/v1/
请求头 跨域时,引发发送多次请求
4、面向资源编程: 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
5、method
GET :从服务器取出资源(一项或多项)
POST :在服务器新建一个资源
PUT :在服务器更新资源(客户端提供改变后的完整资源)
PATCH :在服务器更新资源(客户端提供改变的属性)
DELETE :从服务器删除资源
6、过滤,通过在url上传参的形式传递搜索条件
https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
7、状态码
'''1. 2XX请求成功'''
# 200 请求成功,一般用于GET与POST请求
# 201 Created - [POST/PUT/PATCH]:用户新建或修改数据成功。
# 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
# 204 NO CONTENT - [DELETE]:用户删除数据成功。
'''2. 3XX重定向'''
# 301 NO CONTENT - 永久重定向
# 302 NO CONTENT - 临时重定向
'''3. 4XX客户端错误'''
# 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误。
# 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
# 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
# 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录。
# 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
# 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
# 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
'''4. 5XX服务端错误'''
# 500 INTERNAL SERVER ERROR - [*]:服务器内部错误,无法完成请求
# 501 Not Implemented 服务器不支持请求的功能,无法完成请求更多状态码参考:https://www.runoob.com/http/http-status-codes.html
django实现restful
# urls.py
urlpatterns = [
url(r'^users', Users.as_view()),
]
# views.py
from django.views import View
from django.http import JsonResponse
class Users(View):
def get(self, request, *args, **kwargs):
result = {
'status': True,
'data': 'response data'
}
return JsonResponse(result, status=200)
def post(self, request, *args, **kwargs):
result = {
'status': True,
'data': 'response data'
}
return JsonResponse(result, status=200)
基于drf框架实现
1.serializer-APIView
# models.py
class Classroom(models.Model):
"""
班级表
"""
class_name = models.CharField(max_length=32, verbose_name="班级名称", unique=True)
address = models.CharField(max_length=32, null=True)
class Meta:
db_table = "pp_class"
def __str__(self):
return self.class_name
# serializer.py
class ClassroomSerializer(serializers.Serializer):
class_name = serializers.CharField(max_length=32, required=True, label='班级名')
address = serializers.CharField(max_length=32, label='地址')
def create(self, validated_data):
return Classroom.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.class_name = validated_data.get('class_name', instance.class_name)
instance.address = validated_data.get('address', instance.address)
instance.save()
return instance
# views.py
class ClassroomView(APIView):
def get(self, request):
# 查询
class_obj = Classroom.objects.all().order_by('-id')
ser_obj = ClassroomSerializer(class_obj , many=True)
return Response(ser_obj.data)
def post(self, request):
# 添加
data = request.data
ser_obj = ClassroomSerializer(data=data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
def put(self, request):
# 修改
data = request.data
instance = Classroom.objects.filter(class_name=data['class_name']).first() # 查询要修改的对象
ser_obj = ClassroomSerializer(instance=instance, data=data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
添加时数据自定义验证
方法一:在views中验证
# serializer.py
class ClassroomSerializer(serializers.Serializer):
class_name = serializers.CharField(max_length=32, required=True, label='班级名')
address = serializers.CharField(max_length=32, label='地址')
def create(self, validated_data):
return Classroom.objects.create(**validated_data)
# views.py
class ClassroomView(APIView):
def post(self, request):
data = request.data
# 验证地址 是不是 beijing
if data['address'] != 'beijing':
return Response({'msg': '信息不在北京'})
ser_obj = ClassroomSerializer(data=data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
方法二:序列化中验证
# serializer.py
class ClassroomSerializer(serializers.Serializer):
class_name = serializers.CharField(max_length=32, required=True, label='班级名')
address = serializers.CharField(max_length=32, label='地址')
def create(self, validated_data):
return Classroom.objects.create(**validated_data)
# 自定义验证规则
def validate(self, attrs):
if attrs.get('address') != 'beijing':
raise serializers.ValidationError('信息不在北京')
return attrs
# views.py
class ClassroomView(APIView):
def post(self, request):
data = request.data
ser_obj = ClassroomSerializer(data=data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
多对多一对多序列化嵌套
# models.py
from django.db import models
class Role(models.Model):
"""
角色表
"""
role_name = models.CharField(max_length=32, unique=True)
class Meta:
db_table = "pp_role"
class Classroom(models.Model):
"""
班级表
"""
class_name = models.CharField(max_length=32, verbose_name="班级名称", unique=True)
address = models.CharField(max_length=32, null=True)
class Meta:
db_table = "pp_class"
def __str__(self):
return self.class_name
class User(models.Model):
"""
用户表
"""
username = models.CharField(max_length=32, verbose_name="姓名")
age = models.IntegerField(verbose_name="年龄")
home = models.CharField(verbose_name="家乡", null=True, max_length=32)
hight = models.IntegerField(verbose_name="身高", null=True)
# 多对多
roles = models.ManyToManyField(Role)
# 一对多
classrooms = models.ForeignKey(Classroom, on_delete=models.CASCADE, null=True)
class Meta:
db_table = "pp_user"
# serializer.py
from rest_framework import serializers
from .models import *
class ClassroomSerializer(serializers.Serializer):
class_name = serializers.CharField(max_length=32, required=True, label='班级名')
address = serializers.CharField(max_length=32, label='地址')
class RoleSerializer(serializers.Serializer):
role_name = serializers.CharField(max_length=32, required=True, label='角色名')
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=32)
age = serializers.IntegerField()
home = serializers.CharField(max_length=32, allow_null=True)
hight = serializers.IntegerField(allow_null=True)
# 多对多
roles = RoleSerializer(many=True)
# 一对多
classrooms = ClassroomSerializer()
# views.py
# 查询用户
class UserView(APIView):
def get(self, request):
# 查询
user_obj = User.objects.all()
ser_obj = UserSerializer(user_obj, many=True)
return Response(ser_obj.data)
查询结果:
[
{
"username": "张三",
"age": 22,
"home": "北京",
"hight": 180,
"roles": [
{
"role_name": "教师"
},
{
"role_name": "警察"
}
],
"classrooms": {
"class_name": "2002A",
"address": "北京"
}
},
{
"username": "李四",
"age": 33,
"home": "啊啊",
"hight": 180,
"roles": [
{
"role_name": "教师"
}
],
"classrooms": {
"class_name": "2002B",
"address": "beijing"
}
},
{
"username": "王五",
"age": 22,
"home": "北京",
"hight": 180,
"roles": [],
"classrooms": {
"class_name": "2002c",
"address": "beij"
}
}
]
用户访问次数/频率限制
全局使用
# settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}
分页
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from .serializer import *
class PageNum(PageNumberPagination):
# 指定查询字符串中代表每页返回数据数量的参数名,默认None
page_size_query_param = "max_page"
# 指定查询字符串中代表页码的参数名,不指定默认值page
# page_query_param = 'page'
# max_page_size = 10 # 一页最多的结果条数,
class ClassroomView(APIView):
def get(self, request):
class_obj = Classroom.objects.all().order_by('-id')
# 分页
paginator = PageNum()
result_page = paginator.paginate_queryset(class_obj, request)
ser_obj = ClassroomSerializer(result_page, many=True)
return Response(ser_obj.data)