Django rest framework——2
1. 版本
URL中通过GET传参()
a. 自定义:
http://127.0.0.1:8000/api/users/?version=v2
from rest_framework.versioning import BaseVersioning
class ParamVersion(BaseVersioning):
def determine_version(self, request, *args, **kwargs):
# version = request._request.GET.get('version')
version = request.query_params.get('version')
return version
class UsersView(APIView):
versioning_class = ParamVersion
def get(self, request, *args, **kwargs):
print(request.version)
return HttpResponse('用户列表')
b. 使用QueryParameterVersioning:
http://127.0.0.1:8000/api/users/?version=v3
# 在配置文件中设置了默认版本是v3,允许同版本是v1,v1。实际上允许的版本是v1,v2,v3,。但是通常情况下不会这么做。
class UserView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
print(request.version)
return HttpResponse('用户列表')
REST_FRAMEWORK = {
"DEFAULT_VERSION": "v2",
"VERSION_PARAM": "version",
"ALLOWED_VERSIONS": ['v1', 'v2']
在URL中传参(推荐使用)
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view()),
]
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION": 'v1', # 该方式下默认值无效
"ALLOWED_VERSIONS": ['v1', 'v2'],
"VERSION_PARAM": 'version',
}
class UsersView(APIView):
def get(self, request, *args, **kwargs):
print(request.version)
return HttpResponse('用户列表')
}
总结:
配置文件:
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION": 'v1',
"ALLOWED_VERSIONS": ['v1', 'v2'],
"VERSION_PARAM": 'version',
}
路由系统:
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^api/', include('api.urls')),
]
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(), name='uuu'),
]
视图:
class UsersView(APIView):
def get(self, request, *args, **kwargs):
# 1. 获取版本
print(request.version)
# 2. 获取处理版本的对象
print(request.versioning_scheme)
# 3. 通过版本对象,反向生成版本url(rest framework)
u1 = request.versioning_scheme.reverse(viewname='uuu', request=request)
print(u1)
# 4. 反向生成URL(Django内置)
u2 = reverse(viewname='uuu', kwargs={'version': 2})
print(u2)
return HttpResponse('用户列表')
2.解析器
作用:用来解析用户提交的数据。
回顾:django:request.POST/ request.body
- 请求头要求:
Content-Type: application/x-www-form-urlencoded
PS: 如果请求头中的 Content-Type: application/x-www-form-urlencoded,request.POST中才
有值(去request.body中解析数据)。
- 数据格式要求:
name=alex&age=18&gender=男
以上两点同时满足request.POST中才有值
正确示例:
a. form表单提交
<form method...>
input...
</form>
b. ajax提交
$.ajax({
url:...
type:POST,
data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男
})
错误示例:
情况一:
$.ajax({
url:...
type:POST,
headers:{'Content-Type':"application/json"}
data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男
})
# body有值;POST无
情况二:
$.ajax({
url:...
type:POST,
headers:{'Content-Type':"application/json"}
data:JSON.stringfy({name:alex,age=18}) # {name:alex,age:18...}
})
# body有值;POST无
# json.loads(request.body)
使用:
from rest_framework.parsers import JSONParser
class ParseView(APIView):
parser_classes = [JSONParser]
# JSONParser:表示只能解析content-type:application/json头
# FormParser:表示只能解析content-type:application/x-www-form-urlencoded头
# 现在可以同时解析两种类型的数据
def post(self, request, *args, **kwargs):
# 允许用户发送JSON格式数据
# content - type: application/json
# {"name": "tom", "age": 18}
# 获取解析后的结果
print(request.data)
return HttpResponse('ParseView')
"""
步骤:
1. 获取用户请求
2. 获取用户请求体
3. 根据用户请求头 和 parser_classes = [JSONParser,FormParser,] 中支持的请求头进行比较
4. JSONParser对象去请求体
5. request.data
"""
3.序列化
作用:将服务端的是数据序列化后传递给浏览器。
(1) 序列化:
a. 单表操作
from rest_framework import serializers
class RoleSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(source="title")
class RolesView(APIView):
def get(self, request, *args, **kwargs):
# roles = models.Role.objects.all()
# ser = MySerializers(instance=roles, many=True)
role = models.Role.objects.all().first()
ser = RoleSerializer(instance=role, many=False) # 当序列化的role是单个对象是many=False,或者缺省。默认many=False
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
b. 连表操作
from rest_framework import serializers
class UserInfoSerializer(serializers.Serializer):
id = serializers.CharField()
username = serializers.CharField()
password = serializers.CharField()
user_type = serializers.CharField(source='get_user_type_display') # choices类型
group = serializers.CharField(source='group.title') # ForeignKey
roles = serializers.SerializerMethodField() # ManyToManyField 自定义显示
def get_roles(self, row): # row 是当前行的对象
rls = row.roles.all()
ret = []
for role in rls:
ret.append({'id': role.id, 'title': role.title})
return ret
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users, many=True)
# print(ser.data)
return HttpResponse(json.dumps(ser.data, ensure_ascii=False))
c. ModelSerializer
用法和功能类似于ModelForm
class UserInfoSerializer(serializers.ModelSerializer):
rls = serializers.SerializerMethodField() # 自定义显示
user_type = serializers.CharField(source='get_user_type_display')
class Meta:
model = models.UserInfo
fields = ['id', 'username', 'password', 'rls', 'user_type', 'rls']
# 自定义方法
def get_rls(self, row):
role_obj_list = row.roles.all()
ret = []
for item in role_obj_list:
ret.append({'id': item.id, 'title': item.title})
return ret
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users, many=True)
# print(ser.data)
return HttpResponse(json.dumps(ser.data, ensure_ascii=False))
自动序列化连表 (depth=num)
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = '__all__'
depth = 1 # 连表查询深度,官方建议0-10
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users, many=True)
# print(ser.data)
return HttpResponse(json.dumps(ser.data, ensure_ascii=False))
d.生成详细链接
views.py:
from rest_framework import serializers
class UserInfoSerializer(serializers.ModelSerializer):
group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk')
# lookup_field: 数据库查询字段 lookup_url_kwarg:无名分组的group_id.
class Meta:
model = models.UserInfo
fields = ['id', 'username', 'password', 'group', 'roles']
depth = 0 # 0 ~ 10
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users, many=True, context={'request': request})
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
urls.py:
from django.conf.urls import url
from api import views
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/userinfo/$', views.UserInfoView.as_view(), name='user'),
url(r'^(?P<version>[v1|v2]+)/group/(?P<pk>\d+)$', views.GroupInfoView.as_view(),name='gp'),
]
settings:
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION": "v1",
"VERSION_PARAM": "version",
"ALLOWED_VERSIONS": ['v1', 'v2']
}
现在来记录一下我在做上面的生成详细链接时遇到的坑(自己给自己刨的坑)。
一开始我的错误是出现在了,urls.py这个文件中,原因是因为我没有给URL家版本,就是没有加(?P<version>[v1|v2]+)/,其实这本身并没有什么错误,但是我的settings.py文件中还设置了全局的版本配置。所以就报错了,报错信息如下。
还有一点就是默认的版本,一定要在允许的版本列表中,虽然不这样做有时也不会出错,但是在生成详细链接就会报错。这两个报错信息都一样。
Could not resolve URL for hyperlinked relationship using view name "gp". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
无法使用视图名称“gp”解析超链接关系的URL。 您可能未能在您的API中包含相关模型,或者未正确配置此字段上的`lookup_field`属性。
(2) 数据验证
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models
class PasswordValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value != self.base:
message = 'This field must be %s.' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 执行验证之前调用,serializer_fields是当前字段对象
pass
class UserSerializer(serializers.Serializer):
ut_title = serializers.CharField(source='ut.title')
user = serializers.CharField(min_length=6)
pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])
class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,将数据库查询字段序列化为字典
data_list = models.UserInfo.objects.all()
ser = UserSerializer(instance=data_list, many=True)
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)
def post(self, request, *args, **kwargs):
# 验证,对请求发来的数据进行验证
ser = UserSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('POST请求,响应内容')

浙公网安备 33010602011771号