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请求,响应内容')

  

 

 

posted @ 2018-03-07 18:49  流星之泪  阅读(301)  评论(0)    收藏  举报