eighth_序列化及其视图

 

2.序列化器的使用:

  2.1 在客户端请求时,使用序列化器完成数据的反序列化(把字节序列恢复为对象的过程称为对象的反序列化)

  2.2 在服务器响应时,使用序列器可以完成对数据的序列化(把对象转换为字节序列的过程称为对象的序列化)

  2.3 数据验证

    使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
  在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

    验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。
如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。 验证成功,可以通过序列化器对象的
**validated_data**属性获取数据。

  相关代码,结合上一章

# 创建一个unsers
python manage.py startapp unsers
# 创建serializer 序列化器(即一个py文件)
from rest_framework import serializers
from students.models import Student


def check_age(age):  # 该方法比较少用,限制年龄不可为50
    if age == 50:
        raise serializers.ValidationError("年龄不能刚好是50")
    return age


class StudentSerializer(serializers.Serializer):
    # 需要转换的字段声明
    # 小括号里面声明主要提供给反序列化使用的
    id = serializers.IntegerField(read_only=True)  # 只读时可调用
    name = serializers.CharField(required=True, max_length=20)
    age = serializers.IntegerField(max_value=150, min_value=0, required=True, validators=[check_age])
    sex = serializers.BooleanField(default=True, write_only=True)
    description = serializers.CharField(required=True, allow_null=True, allow_blank=True)  # 可为空

    # 如果序列化器调用的模型中的字段声明,则需要声明Meta类

    # 验证
    # 序列化器中可以自定义单个字段的验证方法  def validate_<字段名>(用户提交的字段数据):
    def validate_name(self, data):
        if (data == "老男孩"):
            raise serializers.ValidationError("用户名不能是老男孩")

        # 验证完成以后务必要返回字段值
        return data

    # 方法名时固定的,用于验证多个字段,参数就是实例化序列化器类时的data参数
    def validate(self, data):
        name = data.get("name")
        if (name == "python"):
            raise serializers.ValidationError("用户名不能是python")

        age = data.get("age")
        if (age == 0):
            raise serializers.ValidationError("年龄不能是0")

        # 验证完成以后务必要返回data
        return data

    # 添加和更新代码
    # 序列化器中会提供了两个方法: create 和 update,方法名是固定的
    def create(self, validated_data):  # validated_data 参数,在序列化器调用时,会自动传递验证完成以后的数据
        student = Student.objects.create(
            name=self.validated_data.get("name"),
            age=self.validated_data.get("age"),
            sex=self.validated_data.get("sex")
        )

        return student

    def update(self, instance, validated_data):
        """更新学生信息"""
        instance.name = validated_data.get("name")
        instance.sex = validated_data.get("sex")
        instance.age = validated_data.get("age")
        instance.description = validated_data.get("description")
        # 调用模型的save更新保存数据
        instance.save()

        return instance

 

# 视图py文件
# Create your views here.
from django.http import JsonResponse
from django.views import View
from .serializers import StudentSerializer
from students.models import Student


class StudentView(View):
    def post(self, request):
        """添加一个学生"""
        # 接受参数
        post_data = request.POST
        data = {
            "name": post_data.get('name'),
            "age": post_data.get('age'),
            "sex": post_data.get('sex'),
            "description": post_data.get('description'),
        }
        # 调用序列化器进行反序列化验证和转换
        serializer = StudentSerializer(data=data)

        # 当验证失败时,可以直接通过声明 raise_exception=True 让django直接跑出异常
        result = serializer.is_valid(raise_exception=True)
        # 1. 先使用字段声明的验证选项
        # 2. 使用validate_<字段>和validate()
        # 3. 使用字段选项中的validators执行外部函数的验证
        print("验证结果:%s" % result)

        # 获取通过验证后的数据
        print(serializer.validated_data)
        # 保存数据
        # student = Student.objects.create(
        #     name=serializer.validated_data.get("name"),
        #     age=serializer.validated_data.get("age"),
        #     sex=serializer.validated_data.get("sex")
        # )

        # 调用序列化器中的save方法,save会自动调用create
        student = serializer.save()

        print(student)
        # 返回响应结果给客户端
        # alt + enter,可以实现快速导包
        return JsonResponse({"message": "ok"})

    def put(self, request):
        """更新学生信息"""
        # 接受参数
        data = {
            "id": 9,
            "name": "abc",
            "age": 18,
            "sex": 1,
        }
        # 获取要修改的数据
        instance = Student.objects.get(pk=data.get("id"))
        # 调用序列化器
        serializer = StudentSerializer(instance=instance, data=data, partial=True)
        # 验证
        serializer.is_valid(raise_exception=True)
        # 转换成模型数据
        student = serializer.save()

        return JsonResponse({"message": "ok"})

    def get(self, request):
        # 获取所有数据
        data_list = Student.objects.all()
        # 使用序列化器进行序列化器
        serializer = StudentSerializer(instance=data_list, many=True)
        # 返回数据给客户端
        return JsonResponse(serializer.data, safe=False)

 

# unsers里的urls
from django.urls.conf import path
from . import views

urlpatterns = [
    path(r"student/", views.StudentView.as_view()),
]

# 主urls
urlpatterns = [
    .....
    path("unser/", include("unsers.urls")),
]

 

3.模型类序列化器

  

  如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

  ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段

  • 基于模型类自动为Serializer生成validators,比如unique_together

  • 包含默认的create()和update()的实现

代码部分

# serializer
from rest_framework import serializers
from students.models import Student


class StudentModelSerializer(serializers.ModelSerializer):
    # 额外字段声明,必须在fields里面也要声明上去,否则序列化器不会调用
    # password2 = serializers.CharField(write_only=True,required=True)

    # 如果模型类序列化器,必须声明本次调用是哪个模型,模型里面的哪些字段
    class Meta:
        model = Student
        # fields = ["id","name","age","description","sex","password2"]
        fields = ["id", "name", "age", "description", "sex"]
        # fields = "__all__" # 表示操作模型中的所有字段
        # 添加额外的验证选项
        extra_kwargs = {
            "sex": {"write_only": True, },
            "id": {"read_only": True, }
        }

    # 验证代码
    def validate_name(self, data):
        if (data == "老男孩"):
            raise serializers.ValidationError("用户名不能是老男孩")

        # 验证完成以后务必要返回字段值
        return data

    # 也可以重新声明一个create和update

 

# view里
from django.views import View
from students.models import Student
from .serializers import StudentModelSerializer
from django.http.response import JsonResponse


class StudentView(View):
    def get(self, request):
        # 获取数据
        data_list = Student.objects.all()
        # 调用序列化器
        serializer = StudentModelSerializer(instance=data_list, many=True)

        # 响应数据
        return JsonResponse(serializer.data, safe=False)

    def post(self, request):
        data = {
            "name": "老男孩",
            "age": 18,
            "sex": 1,
        }
        # 调用序列化器
        serializer = StudentModelSerializer(data=data)
        # 验证
        serializer.is_valid(raise_exception=True)
        # 转换成模型数据
        student = serializer.save()

        return JsonResponse({"message": "ok"})

 

# 副urls
from django.urls.conf import path
from . import views

urlpatterns = [
    path(r"student/", views.StudentView.as_view())
]


# 主urls
urlpatterns = [
    ......
    path("mser/", include("msers.urls")),
]

 

4. 类视图

  django中一共提供了两种视图:分别是函数视图[function view]和类视图[class view]。

# view
"""函数视图的登录功能"""
# from django.http import HttpResponse
# def login_form(request):
#     """显示登录页面"""
#     if request.method == "GET":
#         html = """
#             <form method="post" action="/clsview/login_data/">
#             账号: <input type="text" name="usernane"><br><br>
#             密码: <input type="password" name="password"><br><br>
#             <input type="submit" value="登录">
#             </form>
#         """
#         return HttpResponse(html)
#
#
# def login_data(request):
#     """验证登录"""
#     print( request.POST )
#
#     return HttpResponse("登录成功")


from django.http import HttpResponse
from django.views import View


class LoginView(View):
    def get(self, request):
        """显示登录页面"""
        html = """
            <form method="post" action="/clsview/login_data/">
            账号: <input type="text" name="usernane"><br><br>
            密码: <input type="password" name="password"><br><br>
            <input type="submit" value="登录">
            </form>
        """
        return HttpResponse(html)

    def post(self, request):
        """处理登录验证"""
        print(request.POST)

        return HttpResponse("登录成功")

# 副urls
from django.urls.conf import path
from . import views

# urlpatterns = [
#     path(r"login_form/",views.login_form),
#     path(r"login_data/",views.login_data),
# ]


urlpatterns = [
    path(r"login/", views.LoginView.as_view()),
]


# 主urls
urlpatterns = [
    ......
    path("clsview/", include("clsview.urls")),
]

 

5. 视图

  drf除了在数据序列化部分简写代码以外,还在视图中提供了简写操作

  Django REST framwork 提供的视图的主要作用:

  • 控制序列化器的执行(检验、保存、转换数据)

  • 控制数据库查询的执行

  • 调用请求类和响应类[这两个类也是由drf帮我们再次扩展了一些功能类。

  5.1 data

  request.data 返回解析之后的请求体数据。类似于Django中标准的request.POSTrequest.FILES属性,但提供如下特性:

  • 包含了解析之后的文件和非文件数据

  • 包含了对POST、PUT、PATCH请求方式解析后的数据

  • 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据

  5.2 query_params

  request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而已。

  5.3 Response

  rest_framework.response.Response

  REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

  REST framework提供了Renderer 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}

  5.4 构造方式

Response(data, status=None, template_name=None, headers=None, content_type=None)

  data数据不用是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer渲染器处理data

  data不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer序列化器序列化处理后(转为了Python字典类型)再传递给data参数。

  参数说明:

  • data: 为响应准备的序列化处理后的数据;

  • status: 状态码,默认200;

  • template_name: 模板名称,如果使用HTMLRenderer 时需指明;

  • headers: 用于存放响应头信息的字典;

  • content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。

  5.5 状态码

  1)信息告知 -1xx

  2)成功 -2xx

  3)重定向 -3xx

  4)客户端错误 -4xx

  5)服务端错误 -5xx

6. 视图基类APIView

  rest_framework.views.APIView

  APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

  APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;

  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;

  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;

  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

  6.1GenericAPIView[通用视图类]

  rest_framework.generics.GenericAPIView

  继承自APIVIew主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。

# 创建一个req
python manage.py startapp req

# view 视图
from django.http import HttpResponse
from django.views import View
from rest_framework.views import APIView
from rest_framework.response import Response

"""drf提供的请求和响应类只能在drf封装过的子视图类中使用,也就是说不能在django.views.View中使用"""
"""只要类视图直接或者间接集成了APIView,则视图方法中使用的request,就是rest_framework.request.Request
同时,只有在APIView的子视图类中才可以使用 rest_framework.response.Response响应类
"""
# 文本根式的状态码
from rest_framework import status


class StudentAPIView(APIView):
    def get(self, request):
        # 获取get参数,request.query_params`与Django标准的`request.GET`相同,只是更换了更正确的名称而已
        print(request.query_params)
        """
        <QueryDict: {'name': ['API'], 'age': ['100']}>
        """
        return Response({"message": "ok"}, status=status.HTTP_204_NO_CONTENT, headers={"COMPANY": "oldboy"})

    def post(self, request):
        # 获取post数据,类似于Django中标准的`request.POST`和 `request.FILES`属性和一些其它属性
        print(request.data)
        """
        <QueryDict: {'name': ['小黑'], 'age': ['51'], 'sex': ['0']}>
        """

        # 获取一个参数值,get参数的获取也是一样用户
        data = request.data.get("lve")
        print(data)
        """美女"""
        # 获取多个参数值,get参数的获取也是一样用户
        # 使用时注意,如果客户端提交的数据时json,则request会自动转换成字典数据,就不再提供getlist方法了.
        data = request.data.getlist("lve")
        print(data)
        # """['篮球', '睡觉', '美女']"""

        return Response({"message": "ok"})


"""以前的django提供的类视图/函数视图,获取json数据"""
import json


class StudentView(View):
    def post(self, request):
        """获取post提交的json数据"""
        # request.POST 只能获取表单数据
        # 获取json类型只能通过body来获取
        data_byte = request.body

        data_string = data_byte.decode()

        # 通过json进行转换
        data_dict = json.loads(data_string)
        print(data_dict)
        """{'name': 'xiaomingf', 'age': 12, 'sex': 1}"""
        return HttpResponse({"message": "ok"})

# 副urls
from django.urls.conf import path
from . import views

urlpatterns = [
    path(r"student/", views.StudentAPIView.as_view()),
    path(r"stu/", views.StudentView.as_view()),
]

# 主urls
urlpatterns = [
    ......
    path("req/", include("req.urls")),
]

 

posted @ 2019-05-06 16:10  pythonernoob  阅读(129)  评论(0)    收藏  举报