Django REST framework (简称:DRF)是一个强大而灵活的 Web API 工具。遵循RESTFullAPI风格,功能完善。
能简化序列化及开发REST API视图的代码,大大提高REST API的开发速度;提供灵活的路由API,内置了强大的认证和授权机制
Django REST framework 最新版使用要求
pip install djangorestframework
在settings.py文件的INSTALLED_APPS添加rest_framework
序列化:将python对象转json
反序列化:将json转为python对象
import json
# 序列化
computer = {"主机":5000,"显示器":1000,"鼠标":60,"键盘":150}
json.dumps(computer)
# 反序列化
json.loads(json_obj)
是Django内置的一个序列化器,可直接将Python QuerySet对象转为JSON格式,但不支持反序列化
from django.core import serializers
obj = User.objects.all()
data = serializers.serialize('json'
, obj)
JsonResponse模块自动将Python对象转为JSON对象并响应。
res = {"code": 200, msg: "查询成功"}
return JsonResponse(res)
DRF中有一个serializers模块专门负责数据序列化,DRF提供的方案更先进、更高级别的序列化方案。
视图里通过ORM从数据库获取数据查询集对象 -> 传入序列化器-> 序列化器将数据进行序列化 -> 调用序列化器的.data获取数据 -> 返回前端
视图获取前端提交的数据 -> 传入序列化器 -> 调用序列化器的.is_valid方法进行效验 -> 调用序列化器的.save()方法保存数据
示例:
class UserSerializer(serializers.Serializer):
# 这里的字段必须与使用模型的字段对应
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=30,
error_messages={ # 设置错误提示
"blank": "请输入姓名",
"required": "该字段必要",
"max_length": "字符长度不超过30",
})
如果常用参数无法满足验证要求时,可通过钩子方法扩展验证规则
class UserSerializer(serializers.Serializer):
…………
# 局部钩子
# 姓名不能包含数字
def validate_name(self, attrs): # attrs是该字段的值
from re import findall
if findall('\d+', attrs):
raise serializers.ValidationError("姓名不能包含数字")
else:
return attrs
在视图函数里面通过如下方法查看异常信息
user_ser = UserSerializer(data=request.data)
print(user_ser.errors)
效果如下:
class UserSerializer(serializers.Serializer):
…………
# 全局钩子
def validate(self, attrs): # attrs是所有字段组成的字典
sex = attrs.get("sex")
if sex not in ['男','女']:
raise serializers.ValidationError("性别只能为男或者女")
else:
return attrs
? Serializer:对Model(数据模型)进行序列化,需自定义字段映射。
? ModelSerializer:对Model进行序列化,会自动生成字段和验证规则,默认还包含简单的create()和update()方法。
? HyperlinkedModelSerializer:与ModelSerializer类似,只不过使用超链接来表示关系而不是主键ID
python manage.py startapp myapp
在settings.py文件的INSTALLED_APPS添加myapp
myapp/models.py
from django.db import models
# Create your models here.
class User(models.Model):
name = models.CharField(max_length=30)
city = models.CharField(max_length=30)
sex = models.CharField(max_length=10)
age = models.IntegerField()
python manage.py makemigrations
python manage.py migrate
创建myapp_api/serializers.py
from rest_framework import serializers
class UserSerializer(serializers.Serializer):
# 这里的字段必须与使用模型的字段对应
id = serializers.IntegerField()
name = serializers.CharField(max_length=30)
city = serializers.CharField(max_length=30)
sex = serializers.CharField(max_length=10)
age = serializers.IntegerField()
from myapp.models import User # 导入模型
from .serializers import UserSerializer # 导入序列化器
from rest_framework.views import APIView
from rest_framework.response import Response
class UserView(APIView):
def get(self, requset):
queryset = User.objects.all() # 获取所有用户
# 调用序列化器将queryset对象转换为json
user_ser = UserSerializer(queryset, many=True) # 如果序列化多条数据,需要指定many=True
return Response(user_ser.data) # 从.data属性获取序列化结果
test01(项目名)/urls.py
from django.contrib import admin
from django.urls import path,re_path,include
urlpatterns = [
path('admin/', admin.site.urls),
re_path('myapp/', include('myapp.urls')),
]
myapp_api/urls.py
from django.urls import re_path
from myapp import views
urlpatterns = [
re_path('^api/user/$', views.UserView.as_view()),
]
访问地址:http://127.0.0.1:8001/myapp/api/user/,可以查看数据
现在数据库是空的,下面写一个POST方法,来实现数据的创建
myapp/views.py,在class UserView的get方法下面增加post方法
def post(self, request):
user_ser = UserSerializer(data=request.data) # 调用序列化器将传入的数据反序列化,转换为Python对象
if user_ser.is_valid(): # 验证数据格式是否正确
user_ser.save() # 保存数据到数据库
msg = '创建用户成功'
code = 200
else:
msg = '数据格式不正确'
code = 400
res = {'code': code, 'msg': msg}
return Response(res)
在myapp/serializers.py下面增加如下方法
from myapp.models import User
def create(self, validated_data): # validated_data为提交的JSON数据
return User.objects.create(**validated_data)
刷新页面,发现下面多了个输入框,右下角有POST
按钮
输入JSON数据,点击POST
返回创建成功
再次查看发现多了条数据
再添加几条数据,结果如下
上面的方法是查看所有用户,那么如何查看单个用户呢?
修改myapp/views.py中的get方法为:
def get(self, requset, pk=None):
if pk:
user_obj = User.objects.get(id=pk) # 获取单个用户数据
user_ser = UserSerializer(user_obj)
else:
queryset = User.objects.all() # 获取所有用户
# 调用序列化器将queryset对象转换为json
user_ser = UserSerializer(queryset, many=True) # 如果序列化多条数据,需要指定many=True
res = {'code': 200, 'msg': '获取用户成功', 'data': user_ser.data}
return Response(res) # 从.data属性获取序列化结果
myapp/urls.py增加如下路由
re_path('^api/user/(?P<pk>\d+)/$', views.UserView.as_view()),
效果
myapp/views.py,在class UserView的get方法下面增加put方法
def put(self, request, pk=None):
user_obj = User.objects.get(id=pk) # 从数据库查找现有的值
#调用序列化器传入已有对象和提交的数据
user_ser = UserSerializer(instance=user_obj, data=request.data)
if user_ser.is_valid():
user_ser.save()
msg = '更新用户成功'
code = 200
else:
msg = '更新用户失败,数据格式不对'
code = 400
res = {'code': code, 'msg': msg}
return Response(res)
在myapp/serializers.py下面增加如下方法
def update(self, instance, validated_data): # instance为当前操作的对象,validated_data为提交JSON数据
instance.name = validated_data.get('name')
instance.city = validated_data.get('city')
instance.sex = validated_data.get('sex')
instance.age = validated_data.get('age')
instance.save()
return instance
实际效果
myapp/views.py,在class UserView的get方法下面增加delete方法
def delete(self, request, pk=None):
user_obj = User.objects.get(id=pk)
try:
user_obj.delete()
msg = '用户删除成功'
code = 200
except Exception as e:
msg = '用户删除失败'
code = 400
res = {'code': code, 'msg': msg}
return Response(res)
效果
ModelSerializer[推荐使用]
ModelSerializer 类型不需要自定义字段映射和定义create、update方法,使用起来方便很多!
? fields:显示所有或指定字段
? exclude:排除某个字段,元组格式,不能与fields同时用
? read_only_fields:只读字段,即只用于序列化,不支持修改
? extra_kwargs:添加或修改原有的字段参数,字典格式
? depth:根据关联的数据递归显示,一般是多表
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User # 指定数据模型
fields = '__all__' # 显示所有字段
#exclude = ('id', ) # 排除字段
read_only_fields = ('id', )
extra_kwargs = {
'name': {'max_length': 30, 'requierd': True},
'city': {'max_length': 10, 'requierd': True},
'age': {'max_length': 30, 'requierd': True},
'sex': {'mix_value': 16, 'max_value': 100, 'requierd': True},
}
与MedelSerializer使用方法一样。只不过它使用超链接来表示关系而不是主键ID。
# 更改序列化器
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = "__all__"
# 更改视图
user_ser = UserSerializer(queryset, many=True, context={'request': request})
# 更改路由
re_path('^api/user/$', views.UserView.as_view(), name="user-detail"),
re_path('^api/user/(?P<pk>\d+)/$', views.UserView.as_view(), name="user-detail")
例如:应用发布系统项目涉及表
一对多:一个项目有多个应用,一个应用只能属于一个项目
多对多:一个应用部署到多台服务器,一个服务器部署多个应用
from django.db import models
# 项目表
class Project(models.Model):
name = models.CharField(max_length=30)
# 应用表
class App(models.Model):
name = models.CharField(max_length=30)
project = models.ForeignKey(Project, on_delete=models.CASCADE) # 一对多
# 服务器表
class Server(models.Model):
hostname = models.CharField(max_length=30)
ip = models.GenericIPAddressField()
app = models.ManyToManyField(App) # 多对多
from rest_framework import serializers
from myapp.models import Project, App, Server
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = "__all__"
class AppSerializer(serializers.ModelSerializer):
class Meta:
model = App
fields = "__all__"
class ServerSerializer(serializers.ModelSerializer):
class Meta:
model = Server
fields = "__all__"
from rest_framework.views import APIView
from rest_framework.response import Response
from myapp.models import Project, App, Server
from .serializers import ProjectSerializer, AppSerializer, ServerSerializer
class ProjectView(APIView):
def get(self, request):
queryset = Project.objects.all() # 获取所有用户
project_ser = ProjectSerializer(queryset, many=True)
res = {'code': 200, 'msg': '获取用户成功', 'data': project_ser.data}
return Response(res) # 从.data属性获取序列化结果
def post(self, requset):
project_ser = ProjectSerializer(data=requset.data)
project_ser.is_valid(raise_exception=True)
project_ser.save()
return Response(data=project_ser.data)
class AppView(APIView):
def get(self, request):
queryset = App.objects.all() # 获取所有用户
app_ser = AppSerializer(queryset, many=True)
res = {'code': 200, 'msg': '获取用户成功', 'data': app_ser.data}
return Response(res) # 从.data属性获取序列化结果
def post(self, requset):
app_ser = AppSerializer(data=requset.data)
app_ser.is_valid(raise_exception=True)
app_ser.save()
return Response(data=app_ser.data)
class ServerView(APIView):
def get(self, request):
queryset = Server.objects.all() # 获取所有用户
server_ser = AppSerializer(queryset, many=True)
res = {'code': 200, 'msg': '获取用户成功', 'data': server_ser.data}
return Response(res) # 从.data属性获取序列化结果
def post(self, requset):
server_ser = ServerSerializer(data=requset.data)
server_ser.is_valid(raise_exception=True)
server_ser.save()
return Response(data=server_ser.data)
from django.urls import re_path
from myapp import views
urlpatterns = [
re_path('^api/project/$', views.ProjectView.as_view()),
re_path('^api/app/$', views.AppView.as_view()),
re_path('^api/server/$', views.ServerView.as_view()),
]
python manage.py makemigrations
python manage.py migrate
打开python控制台
#创建项目:
from myapp.models import Project, App, Server
Project.objects.create(name="电商")
Project.objects.create(name="教育")
#创建应用并指定项目:
project_obj = Project.objects.get(name="电商")
App.objects.create(name="portal", project=project_obj)
App.objects.create(name="gateway", project=project_obj)
#创建服务器:
Server.objects.create(hostname="test1", ip="192.168.31.10")
Server.objects.create(hostname="test2", ip="192.168.31.11")
#将应用部署到服务器:
app_obj = App.objects.get(name="portal")
server_obj = Server.objects.get(hostname="test1")
server_obj.app.add(app_obj)
结果如下:
序列化器返回的是当前模型中的字段,如果字段是外键时,返回的是外键对应id。如下图所示
有两种解决方法
定义字段为外键对应序列化类,这种适合针对某个外键字段
例如:
project=ProjectSerializer(read_only=True) # 一对多
app = AppSerializer(many=True) # 多对多
序列化类中Meta类启用depth:深度获取关联表数据,这种所有外键都会显示出来
效果如下:
DRF序列化器默认仅返回数据模型中已存在资源,如果想新增返回字段或者二次处理,该
如何操作呢?用SerializerMethodFiled
class ProjectSerializer(serializers.ModelSerializer):
app_count = serializers.SerializerMethodField
class Meta:
model = Project
fields = "__all__"
# get_字段名
def get_app_count(self, obj):
return len(obj.app_get.all())
可以通过重写下面两个方法改变序列化和反序列化的行为:
? to_internal_value():处理反序列化的输入数据,自动转换Python对象,方便处理。
? to_representation():处理序列化数据的输出
如果提交API的数据与序列化器要求的格式不符合,序列化器就会出现错误。
这时就可以重写to_internal_value()方法只提取出我们需要的数据
https://www.aliangedu.cn/course/learn?cid=20&sid=10&pid=2197