drf之序列化组件

一、序列化组件的使用

首先,序列化我们可以用for循环实现,但是对于序列化时间是行不通的,所以就需要使用其他方法来实现

  • 用Django的序列化工具

views.py 中文件导入 serializers

from django.core import serializers
from django.shortcuts import HttpResponse
from rest_framework.views import APIView


# 用Django的序列化工具
class Book(APIView):
    def get(self, request):
        response = {'status': 100, 'data': None}
        books = models.Book.objects.all()
        # res 已经是序列化之后的结果
        res = serializers.serialize('json', books)
        response['data'] = res
        return HttpResponse(res)s)

拿到的数据如下,造成的问题就是对于结果来说我们不可控,它会自动加上model、pk,会增加数据的传输量

  • 用drf的序列化组件

首先,导入Serializer类,然后自定义类继承Serializer,这样就可以只针对我们需要的字段进行序列化即可

from rest_framework import serializers
from django.http import JsonResponse


class BookSer(serializers.Serializer):
    # 变量名为字段名,原来的models.py中字段设定的任何数据类型都可以用CharField接收
    name = serializers.CharField()
    price = serializers.CharField()


class Book(APIView):
    def get(self, request):
        books = models.Book.objects.all()
        # BookSer的参数1:instance:queryset对象
        # 序列化多条数据时
        res = BookSer(books, many=True)

        # 序列化一条数据时,如:
        # book = models.Book.objects.filter(id=1)
        # res = BookSer(book, many=False)

        # import json
        # return HttpResponse(json.dumps(res.data))

        # ser.data 拿到的是字典,字典里可能套了列表,所以加上safe=False
        return JsonResponse(res.data, safe=False)

这样拿到的结果就只有我们自己定义的name和price字段

 

二、rest framework的Serializer

表关系建立

from django.db import models


# Create your models here.

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()

    publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name


class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail', to_field='nid', unique=True, on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    address = models.CharField(max_length=64)


class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name

    def test(self):
        return self.email
models.py

新建一个py文件

from rest_framework import serializers


class BookSer(serializers.Serializer):
    # 为字段起别名用source
    abc = serializers.CharField(source='name')
    # 跨表查询时用 字段名.另一张表中的字段名
    pub = serializers.CharField(source='publish.name')
    # age = serializers.CharField()

    # 拿到书籍的出版社信息(字典类型)
    publish = serializers.SerializerMethodField()

    # 该方法必须与SerializerMethodField连用,且必须有返回值
    def get_publish(self, obj):
        # obj 是当前的book对象
        dic = {'name': obj.publish.name, 'email': obj.publish.email}
        return dic

    # 拿到书籍的作者信息(列表套字典)
    author = serializers.SerializerMethodField()

    def get_author(self, obj):
        author_list = []
        authors = obj.authors.all()
        for author in authors:
            author_list.append({'name': author.name, 'age': author.age, 'birthday': author.author_detail.birthday})
        return author_list
my_serilaizer.py
from rest_framework import serializers


class AuyhorSer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.CharField()
    birthday = serializers.CharField(source='author_detail.birthday')


class BookSer(serializers.Serializer):
    # 为字段起别名用source
    abc = serializers.CharField(source='name')
    # 跨表查询时用 字段名.另一张表中的字段名
    pub = serializers.CharField(source='publish.name')
    # age = serializers.CharField()

    # 拿到书籍的出版社信息(字典类型)
    publish = serializers.SerializerMethodField()

    # 该方法必须与SerializerMethodField连用,且必须有返回值
    def get_publish(self, obj):
        # obj 是当前的book对象
        dic = {'name': obj.publish.name, 'email': obj.publish.email}
        return dic

    # 拿到书籍的作者信息(列表套字典)
    author = serializers.SerializerMethodField()

    # 方法一:不用序列化类
    # def get_author(self, obj):
    #     author_list = []
    #     authors = obj.authors.all()
    #     for author in authors:
    #         author_list.append({'name': author.name, 'age': author.age, 'birthday': author.author_detail.birthday})
    #     return author_list

    # 方法二:用序列化类的方法
    def get_author(self, obj):
        authors = obj.authors.all()
        res = AuyhorSer(authors, many=True)
        return res.data
views.py

拿到的结果如下

[
    {
        "abc": "雷神",
        "pub": "环球出版社",
        "publish": {
            "name": "环球出版社",
            "email": "aaa@xxx.al"
        },
        "author": [
            {
                "name": "jack",
                "age": 23,
                "birthday": "2018-12-10"
            },
            {
                "name": "Bob",
                "age": 21,
                "birthday": "2018-06-26"
            }
        ]
    },
    {
        "abc": "奇异博士",
        "pub": "华夏出版社",
        "publish": {
            "name": "华夏出版社",
            "email": "123@qq.com"
        },
        "author": [
            {
                "name": "jack",
                "age": 23,
                "birthday": "2018-12-10"
            }
        ]
    }
]

三、rest framework的ModelSerializer

from ser import models


class BookSer(serializers.ModelSerializer):
    class Meta:
        model = models.Book

        # 拿到全部的数据,用__all__
        fields = '__all__'  # 结果1

        # exclude表示除了,不能跟fields同时用
        exclude = ('name',)   # 结果2

        # 只拿到部分需要的数据,可以用列表
        # fields = ['name', 'price']

        # 按深度查询,1-10
        # depth = 2
  # 使用__all__查询时,可以重写字段方法
    publish = serializers.SerializerMethodField()

    # 该方法必须与SerializerMethodField连用,且必须有返回值
    def get_publish(self, obj):
        # obj 是当前的book对象
        dic = {'name': obj.publish.name, 'email': obj.publish.email}
        return dic

结果①如下

 结果②如下

 

四、rest framework请求数据校验

from django.conf.urls import url
from django.contrib import admin
from ser import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^book/', views.Books.as_view()),
    url(r'^book/(?P<pa>\d+)', views.Books.as_view()),
    url(r'^publish/(?P<pa>\d+)', views.Publish.as_view(), name='aaa'),
]
urls.py
from rest_framework import serializers
from ser import models
from rest_framework.exceptions import ValidationError

class BookSer(serializers.ModelSerializer):
    class Meta:
        model = models.Book

        fields = '__all__'

    name = serializers.CharField(min_length=3, error_messages={'min_length': '不能少于3个字符长度'})

    # required 可以设置字段是否为必填或不必填
    author = serializers.CharField(required=False)

    # 局部钩子
    def validate_name(self, attrs):
        if attrs.startswith('xx'):
            raise ValidationError('拒绝xx开头')
        else:
            return attrs

    # 全局钩子
    def validate(self, attrs):
        # attrs 是所有已经校验通过的数据,字典类型
        price1 = attrs.get('price1')
        price2 = attrs.get('price2')
        if price1 and price2:
            if price1 == price2:
                return attrs
            else:
                raise ValidationError('价格不等')
        return attrs
my_serializer.py
class Auth:
    def auth(self, request):
        token = request.GET.get('token')
        res = models.UserInfo.objects.filter(token=token).first()
        if res:
            return None
        else:
            raise exceptions.APIException('请登录')


class BookDetail(APIView):
    authentication_classes = [Auth, ]

    def get(self, request, pk):
        response = {'status': 100, 'msg': '成功'}
        res = models.Book.objects.filter(pk=pk).first()
        if res:
            book_ser = BookSer(res, many=True)
            response['data'] = book_ser.data
        else:
            response['status'] = 101
            response['msg'] = '您查询的不存在'

        return JsonResponse(response, safe=False)

    def put(self, request, pk):
        response = {'status': 100, 'msg': '成功'}
        ret = models.Book.objects.filter(pk=pk).first()
        if ret:
            # 数据校验
            # 不传instance,调save(),往数据库新增数据
            # 传instance,调save(),修改数据
            ser = BookSer(data=request.data, instance=ret)
            if ser.is_valid():
                # ret.name=request.data.get('name')
                ser.save()
            else:
                response['status'] = 101
                response['msg'] = ser.errors
        else:
            response['status'] = 102
            response['msg'] = '修改的对象不存在'
        return JsonResponse(response, safe=False)
views.py
class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)


class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to=UserInfo)
models.py

 

posted @ 2018-12-11 18:00  cnblogs用户  阅读(196)  评论(0编辑  收藏  举报