注意:该文章摘抄之百度,仅当做学习笔记供小白使用,若侵权请联系删除!
RESTful API 规范
REST( Representational State Transfer ) : 表征性状态转移
数据的安全保障:url 链接一般采用https协议传输,可以提高数据交互过程中的安全性
[http和https的区别是:http是未加密的明文传输的,https是ssl加密建立的安全通道]
接口特征表现:https://xxx/api 特征字段api表示是url链接时完成前后端数据交互的
多版本版本共存:xxx/v1 xxx/v2 表示同资源多版本的情况
数据同资源使用名称: xxx/user xxx/shop 特殊接口可使用动词 xxx/login
资源操作的请求方式,常用的增删改查
- xxx/get 获取
- xxx/post 新增
- xxx/put 整体修改
- xxx/patch 局部修改
- xxx/delete 删除
过滤-限制搜索条件
- xxx?limit=10
- xxx?offset=10
- xxx?page=1&page_count=10
- xxx?sortby=name&order=asc
- xxx?id=1
响应状态码:
- 200 常规请求
- 201 创建成功
- 301 永久重定向
- 302 暂时重定向
- 403 请求无权限
- 404 请求路径失败
- 405 请求方法不存在
- 500 服务器异常
不同操作的规范方式:
- get /collection 返回资源列表
- get /collection/resource 返回单个资源对象
- post /collection 返回新生成的资源对象
- put /collection/resource 返回完整的资源对象
- patch /collection/resource 返回完整的资源对象
- delete /collection/resource 返回一个空文档
简述 django rest framework框架的认证流程
当用户进行登录的时候,运行了登录类的as_view()方法,进入了APIView类的dispatch方法 执行self.initialize_request这个方法,里面封装了request和认证对象列表等其他参数
执行self.initial方法中的self.perform_authentication,里面运行了user方法
再执行了user方法里面的self._authenticate()方法
DRF定义
Django Rest Framework 框架是一个用于构建Web API的强大而又灵活的工具
特点:
提供了定义序列化serializer的方法,可根据ORM或其他库自动序列化/反序列化
提供丰富的类视图、Mixin扩展类,简化视图的编写
多种身份认证和权限认证方式的支持
直观的API Web界面
常见序列化器类字段类型与选项
- BooleanField
- CharField
- EmailField
- RegexField
- URLField
- IPAddressField
- IntegerFileld
- DecimalField
- DateTimeField
- DateField
- TimeField
- ChoiceField
- MultipleChoiceField
- FileField
- ImageField
- ListField
- DictField
选项参数:
- max_length
- min_length
- allow_blank
- trim_whitespace # 是否截断空白字符
- max_value
- min_value
通用参数:
- read_only
- write_only
- required
- default
- allow_null
- validators # 该字段使用的验证器
- error_messages
- label #显示的字段名称
- help_text # 帮助信息
序列化过程:特征是将python 转化为 json格式数据
语法:serializer(instance=None,data={empty},**kwarg)
运用:instance参数 序列化时使用,data参数反序列时使用
# 响应的Python对象转化为响应报文的json字节流
eg:
student= Student.object.all()
serializer= StudentSerializer(student) # 序列化对象
JSONRenderer().render(serializer.data()) # 字典转json字节流
# JSONRenderer()封装了json.dumps() 转化
关联字段外键的其序列化的定义方式
- 方法1: PrimaryKeyRelatedField 返回关联字段的id
user = serializers.PrimaryKeyRelatedField()
- 方法2: StringRelatedField 返回关联字段模型类__str__方法的内容
user = serializers.StringRelatedField()
3. 方法3:UserInfoSerializer 返回关联对象序列化的所有字段
user = UserInfoSerializer()
4. 方法4: SlugRelatedField 返回关联对象的某个特定具体字段
user = serializers.SlugRelatedField(read_only=True,slug_field='name')
反序列化过程:
[语法:is_valid 方法用于验证是否PASS, validated_data属性获取数据,errors打印错误信息]
# 请求body的json字节流转化为Python对象
eg 保存数据:
data=JSONParser().parse(BytesIO(content)) # json字节流转化为字典
serializer= StudentSerializer(data=data) # 反序列化将字典转为对象
serializer.is_valid() # 检验对象数据,成功True,否则False
serializer.save()
# 注: save() 1. 保存时调用create方法 2.更新时调用update()方法 未定义时调用会报错
eg 修改数据:
user = UserInfo.objects.get(id=1)
data = {'name':'pass','pwd':'xxx'}
ser = UserInfoSerializer(instance=user,data=data)
if ser.is_valid():
ser.save()
模型序列化与反序列化
模型序列化器[ serializers.ModelSerializer]: 快速创建Serializer类,其提供了
1.自动生成一系列字段
2.自动生成validators,如unique_together
3. 包含默认的create、update()的实现
class Addr(serializers.ModelSerializer):
class Meta:
model = UserInfo
fields = "__all__"
fields字段定义:
- 可以指定具体字段 fields = ('id','age')
- exclude 排除字段
- read_only_fields 指定只读字段
修改字段的参数选项:extra_kwargs 可添加或修改原有的选项参数以指定对应的值效验字段规则
class Addr(serializers.ModelSerializer):
class Meta:
model = UserInfo
fields = "__all__"
extra_kwargs ={'pwd':{'min_value':0,'required':True}}
# 原模型
class Student(models.Model):
student_id = models.AutoField(primary_key=True, verbose_name="学生编号")
student_name = models.CharField(max_length=8, verbose_name="学生姓名")
student_gender = models.BooleanField(
choices=([0, "male"], [1, "female"]), default=0, verbose_name="学生性别")
student_class = models.ForeignKey(
to="Classes", verbose_name="所属班级", on_delete=models.CASCADE) # 一个班级多个学生
def __str__(self):
return self.student_name
class Meta:
db_table = ''
managed = True
verbose_name = 'Student'
verbose_name_plural = 'Students'
# 序列化
from .models import Student
from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
student_id = serializers.CharField()
student_name = serializers.CharField()
student_gender = serializers.BooleanField()
student_class = serializers.PrimaryKeyRelatedField(many=False, queryset=Teacher.objects.all())
def to_representation(self, instance):
class = instance.student_class
ret = super(StudentSerializer, self).to_representation(instance)
ret["student_class"] = {
"id": class.id,
"name": class.name
}
return ret
# 反序列化
from .models import Student
from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
GENDER_CHOICES = (
(0, 'female'),
(1, 'male')
)
student_id = serializers.CharField(read_only=True)
student_name = serializers.CharField(required=True, max_length=15, label="学生姓名", help_text="学生姓名")
student_gender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
student_class = serializers.PrimaryKeyRelatedField(many=False, queryset=Idc.objects.all())
swagger在线接口文档
Django REST Swagger 项目已经不维护了,并且不支持最新的Django,
所以可以选择 drf-yasg 项目作为接口文档生成器。
yasg 的功能非常强大,可以同时支持多种文档格式。
'drf_yasg', # 配置drf-yasg (API文档生成器) # 注册app
drf_yasg API文档生成器支持两种模式,互动模式和文档模式,分别配置其对应的路由swagger/和redoc/,并通过with_ui方法去配置这两种模式。
在浏览器中输入url/swagger/,进入互动模式
在浏览器中输入url/redoc/,进入文档模式
修饰视图装饰器api_view
app目录下的views.py文件,添加以下代码。比如这个接口,单纯就是返回一些信息,不想让用户访问,但是又不想让用户知道他没权限访问。
这个接口并没有与数据库有数据交互,只是用了视图装饰器 api_view 处理请求和响应
@api_view('GET')
def testing_api(request):
return Response(data={"retcode":status.HTTP_200_OK,'msg':'loading...'})
这里可以采用swagger_auto_schema装饰器修饰视图函数,operation_summary参数指 接口摘要信息、operation_description指 接口描述信息
views.py
# 导入swagger_auto_schema装饰器
from drf_yasg.utils import swagger_auto_schema
@swagger_auto_schema(method='GET',operation_summary='定制化API', operation_description='loading...')
@api_view('GET')
def testing_api(request):
return Response(data={"retcode":status.HTTP_200_OK,'msg':'loading...'})
# url.py
urlpatterns = [
path('',include(router.urls)),
path('swagger/',schema_view.with_ui('swagger',cache_timeout=0),name='schema-swagger-ui'), #互动模式
path('redoc/',schema_view.with_ui('redoc',cache_timeout=0),name='schema-redoc'), #文档模式
path('testing/',sqtp_view.testing_api),
]
修饰视图集 如果视图采用类或者视图集,视图函数本身是继承父类,没有出现在编写的代码中该如何自定义接口描述呢?
# 导入django装饰器
from django.utils.decorators import method_decorator
@method_decorator(name='list',decorator=swagger_auto_schema(operation_summary='查询数据', operation_description='查询所有教师数据'))
@method_decorator(name='create',decorator=swagger_auto_schema(operation_summary='新增数据', operation_description='新增教师信息数据'))
@method_decorator(name='destroy',decorator=swagger_auto_schema(operation_summary='删除数据', operation_description='删除指定教师信息数据'))
class RequestViewSet(viewsets.ModelViewSet):
queryset = Request.objects.all() # 数据的查询集
serializer_class = RequestSerializer
这里参数 name,list指查询所有数据;create指新增数据;update指修改数据;destroy指删除数据;retrieve指查询单条数据;
rest_framework_simplejwt自定义使用——登录功能
# url.py
from django.urls import path
from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView, TokenObtainPairView
urlpatterns = [
path("login/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("verify/", TokenVerifyView.as_view(), name="token_verify"),
]
# 这三个接口分别是登录、获取新的token、验证token是否有效
# TokenObtainPairView.as_view(),这个接口登录成功后会返回:访问令牌和有效令牌。
Django模型元数据Meta选项详解
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),)
# admin中显示的表名称
verbose_name
# verbose_name加s
verbose_name_plural
rolekey = serializers.SerializerMethodField(read_only=True) # 新增自定义字段
前四个只支持CharField字段,后两个只支持IntegerField字段
通用参数
参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,不用做序列化的输出,也就是只用于数据校验,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
我们的字段默认都是既序列化又需反序列化的。
read_only=True,序列化时序列化出该字段数据,反序列化校验时不校验这个数据
write_only=True,序列化时不序列化这个字段数据,反序列校验时,需要客户端传递这个数据过来进⾏校验
也可以在Meta元类中通过extra_kwargs直接为隐式字段传入额外参数error_messages
class Meta:
model = User
fields = ['id', 'username', 'password', 'mobile', 'passwordConfirm', 'smsCode']
# 给隐式字段 添加/修改属性
extra_kwargs = {
'username': {
'min_length': 5,
'max_length': 20,
'error_messages': {
'min_length': '仅允许5-20个字符的用户名',
'max_length': '仅允许5-20个字符的用户名',
}
},
'password': {
'write_only': True,
'min_length': 8,
'max_length': 20,
'error_messages': {
'min_length': '仅允许8-20个字符的密码',
'max_length': '仅允许8-20个字符的密码',
}
}
}
文件传输
HttpResponse、StreamingHttpResponse和FileResponse区别和选择
Django 提供三种方式实现文件下载功能,分别是:HttpResponse、StreamingHttpResponse和FileResponse
HttpResponse 是所有响应的核心类,它的底层功能类是HttpResponseBase。
StreamingHttpResponse 是在HttpResponseBase 的基础上进行继承与重写的,它实现流式响应输出(流式响应输出是使用Python的迭代器将数据进行分段处理并传输的),适用于大规模数据响应和文件传输响应。
FileResponse 是在StreamingHttpResponse 的基础上进行继承与重写的,它实现文件的流式响应输出,只适用于文件传输响应。
HttpResponse 实现文件下载存在很大弊端,其工作原理是将文件读取并载入内存,然后输出到浏览器上实现下载功能。如果文件较大,该方法就会占用很多内存。对于下载大文件,Django推荐使用StreamingHttpResponse 和FileResponse 方法,这两个方法将下载文件分批写入服务器的本地磁盘,减少对内存的消耗。
StreamingHttpResponse和FileResponse对象的对比和选择
StreamingHttpResponse对象需要一个生成器函数来按需生成要发送的数据块。FileResponse对象支持直接读取文件并以块的形式生成响应数据。
由于FileResponse对象使用Python内置的文件迭代器进行分块传输,因此它对文件大小有一定的限制(默认情况下为django.http.response.FILE_CHUNK_SIZE配置)。如果您需要传输超过该限制的文件,则需要使用StreamingHttpResponse对象进行流式传输。
HttpResponse
设置content_type和Content-Disposition头文件以指示浏览器将文件作为附件下载。
使用HttpResponse对象读取整个文件并将其存储为内存中的字符串,这意味着对于大型文件可能会消耗大量的内存资源。
总结:下载大文件时,该方法不太适用!
import os
from django.http import HttpResponse
def download_file(request):
file_path = '/path/to/my/file.txt'
if os.path.exists(file_path):
with open(file_path, 'rb') as f:
file_data = f.read()
response = HttpResponse(file_data, content_type='application/octet-stream')
response['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(file_path))
return response
else:
return HttpResponse("Sorry, the file you requested does not exist.")
StreamingHttpResponse
使用StreamingHttpResponse对象可以解决使用HttpResponse下载大型文件时内存消耗过高的问题。与HttpResponse不同,StreamingHttpResponse不会一次性将整个文件加载到内存中,而是将数据流式传输到客户端
总结,生成器函数是一种能够在需要时逐步生成数据的Python函数。当您需要处理大型文件或数据时,生成器函数非常有用,因为它们可以在需要时按块生成数据,并且可以避免一次性加载大量数据到内存中。
import os
from django.http import StreamingHttpResponse
def download_file(request):
file_path = '/path/to/my/file.txt'
if os.path.exists(file_path):
def file_iterator(file_path, chunk_size=8192):
with open(file_path, 'rb') as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
yield chunk
response = StreamingHttpResponse(file_iterator(file_path))
response['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(file_path))
return response
else:
return HttpResponse("Sorry, the file you requested does not exist.")
使用FileResponse对象可以有效地传输大型文件,并且它还提供了自动支持断点续传和范围请求等HTTP协议特性。
import os
from django.http import FileResponse
def download_file(request):
file_path = '/path/to/my/file.txt'
if os.path.exists(file_path):
response = FileResponse(open(file_path, 'rb'))
response['Content-Type'] = "application/octet-stream"
response['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(file_path))
return response
else:
return HttpResponse("Sorry, the file you requested does not exist.")
# 通过将内容类型设置为 “application/octet-stream”,浏览器会提示用户保存或打开文件,而不是尝试在浏览器窗口中显示它。
使用FileResponse对象时,Django会自动检测客户端是否支持范围请求(即断点续传),如果支持,它将启用自动断点续传功能。这意味着当用户暂停或取消下载时,他们可以在后续下载时从上次停止的地方继续。
django 使用FileResponse限制文件下载大小
file_path = '/path/to/file'
file_size = os.path.getsize(file_path)
max_size = 10 * 1024 * 1024 # 10 MB
if file_size > max_size:
content_range = 'bytes=0-{0}'.format(max_size - 1)
else:
content_range = None
response = FileResponse(open(file_path, 'rb'), content_type='application/octet-stream', content_range=content_range)
如果文件大小超过了最大大小,就将 content_range 设置为 ‘bytes=0-{max_size-1}’,表示只传输前 10 MB 的数据;否则,将 content_range 设置为 None,表示传输整个文件。
上传文件读取
Django 读取excel里的数据导入到数据库表中(使用第三方库openxl) 从Excel表批量导入数据到Django的数据库中一定要注意2条:
校验数据,因为Excel表格里的数据没有约束,经常会出现数据不符合数据表字段约束条件的情况,若不校验会导致大量数据读出来以后存数据库时报错,导致写进数据库的操作失败! 批量导入一定要开启事务。
开启事务的批量导入有2个特点:要么全部导入成功,要么全部导入失败。
django+xlsxwriter导出excel Xlsxwriter 使用 FileResponse类返回
利用序列化器实现增删改查接口
def user_list(request):
if request.method =='GET':
users= UserInfo.objects.all()
serializer= UserInfoSerializer(users,many=True) # many=True 代表序列化多条数据
return JsonResponse(serializer.data,safe=False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = UserInfoSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data,status=201)
def user_detail(request,id):
try:
user = UserInfo.objects.get(id=id)
except UserInfo.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'GET':
serializer = UserInfoSerializer(user)
return JsonResponse(serializer.data)
elif request.method =='PUT':
data = JSONParser().parse(request)
serializer = UserInfoSerializer(user,data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors,status=400)
elif request.method =='DELETE':
user.delete()
return HttpResponse(status=204)
url.py 实现
urlpatterns = [
path('user/<int:id>/', views.user_detail()),
]
自定义序列化器的效验方法
规范:validate_字段名
# 方式1:
class UserInfoSerial(serializers.Serializer):
def validated_pwd(self,value):
if not 10< len(value)<20:
raise serializers.ValidationError('字段的长度不在10-20位之间')
# 方式2:
def validated_pwd(self,value):
if not 10< len(value)<20:
raise serializers.ValidationError('字段的长度不在10-20位之间')
# 序列化器通过validators调用函数
pwd = serializers.CharField(validators=validated_pwd)
DRF定义请求和响应
"""
Django的request
request.GET # 获取get请求的参数
request.POST # 获取post请求传递的表单参数
put、patch # post 请求传递的请求体参数(json格式),Django未定义其直接获取的方法
request.body.decode()
import json
params = json.loads(params)
DRF的request对象:
1. 对应的查询参数 request.query_params
2. 对应表单json参数获取(请求体) request.data
"""
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET','POST'])
def user_list1(request):
return Response(data={'message':'OK'})
DRF 的Response对象:使用该类构造响应对象时,响应的具体内容会转化成符合前端需求的类型
from rest_framework.response import Response
return Response(data=None,status=None,template_name=None,headers=None,content_type=None)
API视图的装饰器
REST框架提供了两个可用编写的API视图的包装器:
- 视图装饰器 @api_view
- 类视图 APIView
@api_view实现增删改查的接口优化
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
@api_view(['GET','POST'])
def user_list(request):
if request.method =='GET':
users= UserInfo.objects.all()
serializer= UserInfoSerializer(users,many=True) # many=True 代表序列化多条数据
result = {'data':serializer.data,'message':'ok'}
return Response(result, status.HTTP_201_CREATED)
elif request.method == 'POST':
serializer = UserInfoSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
result = {'data': serializer.data, 'message': 'ok'}
return Response(result,status.HTTP_201_CREATED)
result = {'data': serializer.errors, 'message': 'fail'}
return Response(result,status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET','PUT','DELETE'])
def user_detail(request,id):
try:
user = UserInfo.objects.get(id=id)
except UserInfo.DoesNotExist:
return Response({'code':404,'message':'fail'},status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = UserInfoSerializer(user)
return Response({'code': 204, 'message': serializer.data}, status=status.HTTP_204_NO_CONTENT)
elif request.method =='PUT':
data = JSONParser().parse(request)
serializer = UserInfoSerializer(user,data=data)
if serializer.is_valid():
serializer.save()
return Response({'code': 200, 'message': 'OK'}, status=status.HTTP_200_OK)
return Response({'code': 400, 'message': 'fail'}, status=status.HTTP_400_BAD_REQUEST)
elif request.method =='DELETE':
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
使用DRF给url添加后缀:
- 访问:/xxx.json 返回json格式
- 访问:/xxx.api 访问DRF自带的接口调试页面
更新url文件
from django.urls import path
from . import views
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path('user/', views.user_list()),
path('user/<int:id>/', views.user_detail()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
# format_suffix_patterns 格式化数据 支持url添加后缀
# 更新views.py 添加参数format
def user_list(request,format=None)
类视图APIView
APIView和View的区别:
- 传入到视图方法的是REST framework的Request对象
- 视图返回的是REST framework的Resopnse对象
- 任何APIException 异常会被捕捉,并处理成合适的响应信息
- 扩展了身份认证、权限检查、流量控制三个功能
APIView实现增删改查的优化
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser
from .models import UserInfo
from .serializers import UserInfoSerializer
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
class UserListView(APIView):
def get(self, request, format=None):
users = UserInfo.objects.all()
serializer = UserInfoSerializer(users, many=True) # many=True 代表序列化多条数据
result = {'data': serializer.data, 'message': 'ok', 'code': 201}
return Response(result, status.HTTP_201_CREATED)
def post(self, request, format=None):
serializer = UserInfoSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
result = {'data': serializer.data, 'message': 'ok', 'code': 201}
return Response(result, status.HTTP_201_CREATED)
result = {'data': serializer.errors, 'message': 'fail', 'code': 400}
return Response(result, status=status.HTTP_400_BAD_REQUEST)
class UserDetailView(APIView):
def get_object(self,id):
try:
return UserInfo.objects.get(id=id)
except UserInfo.DoesNotExist:
return Response({'code': 404, 'message': 'fail'}, status=status.HTTP_404_NOT_FOUND)
def get(self, request, id, format=None):
"获取单个资源"
user = self.get_object(id)
serializer = UserInfoSerializer(user)
return Response({'code': 204, 'message': serializer.data}, status=status.HTTP_204_NO_CONTENT)
def delete(self, request, id, format=None):
user = self.get_object(id)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
def put(self, request, id, format=None):
user = self.get_object(id)
serializer = UserInfoSerializer(user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'code': 200, 'message': 'OK'}, status=status.HTTP_200_OK)
return Response({'code': 400, 'message': 'fail'}, status=status.HTTP_400_BAD_REQUEST)
urls文件更新
from django.urls import path
from . import views
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path('user/<int:id>/', views.UserDetailView.as_view()),
path('user/', views.UserListView.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
APIView视图类的封装优化
class UserView(APIView):
model = UserInfo # set model
ser = UserInfoSerializer
def get(self, request, format=None):
users = self.model.objects.all()
serializer = self.ser(users, many=True) # many=True 代表序列化多条数据
result = {'data': serializer.data, 'message': 'ok', 'code': 201}
return Response(result, status.HTTP_201_CREATED)
def post(self, request, format=None):
serializer = self.ser(data=request.data)
if serializer.is_valid():
serializer.save()
result = {'data': serializer.data, 'message': 'ok', 'code': 201}
return Response(result, status.HTTP_201_CREATED)
result = {'data': serializer.errors, 'message': 'fail', 'code': 400}
return Response(result, status=status.HTTP_400_BAD_REQUEST)
class UserDetailView(APIView):
model = UserInfo # set model
ser = UserInfoSerializer
def get_object(self,id):
try:
return self.model.objects.get(id=id)
except UserInfo.DoesNotExist:
return Response({'code': 404, 'message': 'fail'}, status=status.HTTP_404_NOT_FOUND)
def get(self, request, id, format=None):
"获取单个资源"
user = self.get_object(id)
serializer = self.ser(user)
return Response({'code': 204, 'message': serializer.data}, status=status.HTTP_204_NO_CONTENT)
def delete(self, request, id, format=None):
user = self.get_object(id)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
def put(self, request, id, format=None):
user = self.get_object(id)
serializer = self.ser(user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'code': 200, 'message': 'OK'}, status=status.HTTP_200_OK)
return Response({'code': 400, 'message': 'fail'}, status=status.HTTP_400_BAD_REQUEST)
GenericAPIView视图的使用:继承APIView方法多了两个属性,继续优化
1. queryset = xxx.objects.all() 2. serializer_class = xxxSerial
from rest_framework.generics import GenericAPIView
class UserView(GenericAPIView):
queryset = UserInfo.objects.all() # set model
serializer_class = UserInfoSerializer
def get(self, request, format=None):
users = self.get_queryset() # 同 self.queryset
# serializer = self.get_serializer_class() 同 self.get_serializer
serializer = self.get_serializer(users,many=True)
result = {'data': serializer.data, 'message': 'ok', 'code': 201}
return Response(result, status.HTTP_201_CREATED)
def post(self, request, format=None):
serializer =self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
result = {'data': serializer.data, 'message': 'ok', 'code': 201}
return Response(result, status.HTTP_201_CREATED)
result = {'data': serializer.errors, 'message': 'fail', 'code': 400}
return Response(result, status=status.HTTP_400_BAD_REQUEST)
class UserDetailView(GenericAPIView):
queryset = UserInfo.objects.all() # set model
serializer_class = UserInfoSerializer
# def get_object(self,id):
# try:
# return self.model.objects.get(id=id)
# except UserInfo.DoesNotExist:
# return Response({'code': 404, 'message': 'fail'}, status=status.HTTP_404_NOT_FOUND)
def get(self, request, id, format=None):
"获取单个资源"
user = self.get_object() # 同自定义get_object方法,优化
serializer = self.get_serializer(user)
return Response({'code': 204, 'message': serializer.data}, status=status.HTTP_204_NO_CONTENT)
def delete(self, request, id, format=None):
user = self.get_object()
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
def put(self, request, id, format=None):
user = self.get_object()
serializer = self.get_serializer(user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'code': 200, 'message': 'OK'}, status=status.HTTP_200_OK)
return Response({'code': 400, 'message': 'fail'}, status=status.HTTP_400_BAD_REQUEST)
mixins视图集优化: 实现了self.get_serializer、self.get_object接口的实现可进一步封装
其主要的封装的视图
CreateModelMixin:提供create方法快速实现资源的创建 ListModelMixin: 提供list方法快速实现列表视图 RetrieveModelMixin: 获取单一数据,提供retrieve方法,快速返回一个存在的数据对象 UpdateModelMixin: 提供update方法快速更新一个存在的数据对象 DestroyModelMixin:提供destroy方法快速删除一个存在的数据对象
from rest_framework.generics import GenericAPIView,mixins
class UserView(GenericAPIView,mixins.ListModelMixin,mixins.CreateModelMixin):
queryset = UserInfo.objects.all() # set model
serializer_class = UserInfoSerializer
def get(self, request, *args,**kwargs):
return self.list(request,*args,**kwargs) # 继承 ListModelMixin
def post(self, request, *args,**kwargs):
return self.create(request, *args,**kwargs) # 继承 CreateModelMixin
class UserDetailView(GenericAPIView,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin):
queryset = UserInfo.objects.all() # set model
serializer_class = UserInfoSerializer
def get(self, request, *args,**kwargs):
"获取单个资源"
return self.retrieve(request, *args, **kwargs) # 继承 RetrieveModelMixin
def delete(self, request, *args,**kwargs):
return self.destroy(request, *args, **kwargs) # 继承 DestroyModelMixin
def put(self, request, *args,**kwargs):
return self.update(request, *args, **kwargs) # 继承 UpdateModelMixin
视图扩展优化继承类
generics视图扩展类:进一步优化封装
CreateAPIView ListAPIView RetrieveAPIView DestroyAPIView UpdateAPIView
from rest_framework import status,generics
class UserView(generics.ListAPIView,generics.CreateAPIView):
queryset = UserInfo.objects.all() # set model
serializer_class = UserInfoSerializer
"""
ListAPIView # 封装get方法,省略
CreateAPIView # 封装post方法,省略
"""
class UserDetailView(generics.RetrieveAPIView,generics.DestroyAPIView,generics.UpdateAPIView):
queryset = UserInfo.objects.all() # set model
serializer_class = UserInfoSerializer
"""
RetrieveAPIView # 封装get方法单一对象查询,省略
DestroyAPIView # 封装delete方法,省略
UpdateAPIView # 封装put方法,省略
"""
视图集:ViewSet视图不再实现get、post方法,而是实现动作action,如list(),create()一系列动作放到一个类中,而不产生冲突
- list() 提供一组数据
- retrieve() 提供单个数据
- create 创建数据
- update 保存数据
- destory 删除数据
action属性: 只有使用as_view方法是,才会将action动作与请求响应
常见视图集类:
- ViewSet ,继承自APIView ,提供了身份认证、权限效验、流量管理等接口(需要自定义action方法)
- GenericViewSet 继承自GenericAPIView,提供了get_object、get_queryset方法
- ModelViewSet继承自GenericAPIView,同时实现了CreateAPIView、ListAPIView、RetrieveAPIView、DestroyAPIView、UpdateAPIView方法
- ReaOnlyModelViewSet继承自GenericAPIView,同时包括ListModelMixin、RetrieveModelMixin
上述使用ModelViewSet类视图集继续优化,代码效果同上
from rest_framework.viewsets import ModelViewSet
class UserView(ModelViewSet):
queryset = UserInfo.objects.all() # set model
serializer_class = UserInfoSerializer
"""
已实现下列类视图,省略
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet
"""
# url路由更新
from django.urls import path
from . import views
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path('users/', views.UserView.as_view({'get':'list','post':'create'})),
path('users/<int:pk>/', views.UserView.as_view({'get':'retrieve','delete':'destroy','put':'update'})),
]
urlpatterns = format_suffix_patterns(urlpatterns)
路由:Routers快速实现路由信息,下面两个区别是DefaultRouter会多附带一个默认的API根视图,返回所有列表视图
- SimpleRouter-推荐
- DefaultRouter
上面的url路由实现优化
from . import views
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework import routers
# DRF的路由注册只支持视图集(当继承自ViewSet时使用)
router = routers.SimpleRouter()
router.register(r'users',views.UserView)
urlpatterns = []
urlpatterns +=router.urls
urlpatterns = format_suffix_patterns(urlpatterns)