序列化组件进阶

序列化组件进阶

简单认识序列化

1 序列化模型类:api/models.py

# 自定义model类的方法属性,完成插拔式跨表查询
class Book(BaseModel):
    # ...
    @property
    def publish_name(self):
        return self.publish.name
    @property
    def authors_info(self):
        author_list = []
        for author in self.authors.all():
            author_list.append({
                'name': author.name,
                'age': author.age,
                'mobile': author.detail.mobile
            })
        return author_list
    
class Author(BaseModel):
    # ...
    @property
    def mobile(self):
        return self.detail.mobile

2 序列化类:api/serializers.py

from rest_framework import serializers
from . import models

"""
序列化总结:
1)在自定义的ModelSerializer类中设置class Meta
    model 绑定序列化相关的模型类
    fields 插拔方式指定序列化字段
2)在模型类中通过 方法属性 自定义连表查询的字段,在fields中插拔
3)如果就使用外键字段完成连表深度查询,用 序列化深度
    外键字段 = 外键序列化类(many=True|False)
"""
class PublishModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = ('name', 'address')
class AuthorModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.Author
        fields = ('name', 'age', 'mobile')
class BookModelSerializer(serializers.ModelSerializer):
    # 正向序列化深度
    # (不建议:必须用外键名才需要序列化深度,
    # 建议:自定义外键序列化名,在model类中插拔字段(属性方法))
    publish = PublishModelSerializer()
    authors = AuthorModelSerializer(many=True)

    # 了解:在ModelSerializer中不建议使用,如何书写了必须在fields中声明使用
    # p_n = serializers.SerializerMethodField()
    # def get_p_n(self, obj: models.Book):
    #     return obj.publish.name

    class Meta:
        model = models.Book
        fields = ('name', 'price', 'img', 'publish_name', 'authors_info', 'publish', 'authors')

        # 了解
        # fields = '__all__'  # 所有字段
        # # exclude = ('id', 'is_delete')  # 刨除某些字段
        # depth = 1  # 跨表自动深度(展示外键表的所有字段)

3 序列化视图类:api/views.py

from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers
class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        book_query = models.Book.objects.all()
        book_ser = serializers.BookModelSerializer(book_query, many=True)
        return APIResponse(0, 'ok', results=book_ser.data)

简单认识反序列化

反序列化模型类:api/models.py

# 自定义model类的方法属性,完成插拔式跨表查询
class Book(BaseModel):
    # ...
    @property
    def publish_name(self):
        return self.publish.name
    @property
    def authors_info(self):
        author_list = []
        for author in self.authors.all():
            author_list.append({
                'name': author.name,
                'age': author.age,
                'mobile': author.detail.mobile
            })
        return author_list
    
class Author(BaseModel):
    # ...
    @property
    def mobile(self):
        return self.detail.mobile

反序列化类:api/serializers.py


"""
反序列化总结:
1)在自定义的ModelSerializer类中设置class Meta
    model 绑定反序列化相关的模型类
    fields 插拔方式指定反序列化字段
    extra_kwargs 定义系统校验字段的规则
2)可以自定义局部钩子和全局钩子完成字段的复杂校验规则
3)不需要重写create和update完成增加修改,ModelSerializer类已经帮我们实现了
"""
class BookModelDeserializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ('name', 'price', 'publish', 'authors')
        extra_kwargs = {
            'name': {
                'min_length': 3,
                'error_messages': {
                    'min_length': '太短'
                }
            },
            'publish': {
                'required': True
            },
            'authors': {
                'required': True
            },
        }

    # 自定义校验
    # 这个反序列化封装的非常全面
    # 这里面封装了 比如你传过来一个外键名要和orm名字对上,
    def validate_name(self, value):
        if 'sb' in value:
            raise serializers.ValidationError('书名有敏感词汇')
        return value

    def validate(self, attrs):
        name = attrs.get('name')
        publish = attrs.get('publish')
        # 注意这个publish 已经是一个model对象了
        # 这个publish = publish  内部会自动转化为  publish_id = publish.id
        if models.Book.objects.filter(name=name, publish=publish):
            raise serializers.ValidationError({'book': '书籍以存在'})
        return attrs

序列化视图类:api/views.py

from rest_framework.views import APIView
from utils.response import APIResponse

from . import models, serializers
class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        book_query = models.Book.objects.all()
        book_ser = serializers.BookModelSerializer(book_query, many=True)
        return APIResponse(0, 'ok', results=book_ser.data)

    def post(self, request, *args, **kwargs):
        book_ser = serializers.BookModelDeserializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return APIResponse(0, 'ok')
        else:
            return APIResponse(1, '添加失败', results=book_ser.errors)

序列化与反序列化共存(重点)

路由:api/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
    # ...
    url(r'^v2/books/$', views.BookV2APIView.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.BookV2APIView.as_view()),
]

模型层修订:api/models.py

class Book(BaseModel):
    # ...
    class Meta:
        # ...
        # 联合唯一 => patch结果修改部分数据就会收到'name'、'publish'联合限制
        unique_together = ('name', 'publish')

序列化层:api/serializers.py

class BookV2ModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        # 序列化和反序列化一体
# 这个地方先写完反序列化字,并且把只需要反序列化字段的内容摘出来写上write_only:True
#  反序列化字段  'name','price','publish','authors'
#  序列化字段    'name','price','img','publish_name','authors_info' 
#  感觉这个序列化和反序列化不实用。
# 又或者单独做序列化比较实用,反序列化并不实用感觉。

# 使用逻辑:
# 首先写反序列化的内容  都写上 write_only
# 其次写序列化的内容 都写上read_only  如果有和反序列化重合的则去掉之前反序列化的write_only   	
        fields = ('name', 'price', 'publish', 'authors', 'img', 'publish_name', 'authors_info')
        extra_kwargs = {
            'publish': {
                'required': True,
                'write_only': True
            },
            'authors': {
                'required': True,
                'write_only': True
            },
            'img': {
                'read_only': True
            }
        }
    def validate_name(self, value):
        if 'sb' in value:
            raise serializers.ValidationError('书名有敏感词汇')
        return value
    def validate(self, attrs):
        name = attrs.get('name')
        publish = attrs.get('publish')
        # 注意这个publish 已经是一个model对象了
        # 这个publish = publish  内部会自动转化为  publish_id = publish.id
        if models.Book.objects.filter(name=name, publish=publish):
            raise serializers.ValidationError({'book': '书籍以存在'})
        return attrs

视图层:api/views.py

class BookV2APIView(APIView):
    def get(self, request, *args, **kwargs):
        book_query = models.Book.objects.filter(is_delete=False).all()
        book_ser = serializers.BookV2ModelSerializer(book_query, many=True)
        return APIResponse(0, 'ok', results=book_ser.data)

    def post(self, request, *args, **kwargs):
        book_ser = serializers.BookV2ModelSerializer(data=request.data)
        if book_ser.is_valid():
            book_obj = book_ser.save()
            return APIResponse(0, 'ok',
                results=serializers.BookV2ModelSerializer(book_obj).data
            )
        else:
            return APIResponse(1, '添加失败', results=book_ser.errors)
    ## 局部修改
    def patch(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if not pk:
            return APIResponse(1, 'pk error')
        try:
            book_obj = models.Book.objects.get(is_delete=False, pk=pk)
        except:
            return APIResponse(1, 'pk no book')
        book_ser = serializers.BookV2ModelSerializer(partial=True, instance=book_obj, data=request.data)
        if book_ser.is_valid():
            book_obj = book_ser.save()
            return APIResponse(1, 'ok',
                results=serializers.BookV2ModelSerializer(book_obj).data
            )
        else:
            return APIResponse(1, '更新失败', results=book_ser.errors)

    def delete(self, request, *args, **kwargs):
        # 单删 /books/(pk)/
        # 群删 /books/  数据包携带 pks => request.data
        pk = kwargs.get('pk')
        if pk:
            pks = [pk]
        else:
            pks = request.data.get('pks')
        if not pks:
            return APIResponse(1, '删除失败')
        book_query = models.Book.objects.filter(is_delete=False, pk__in=pks)
        print(book_query)
        if not book_query.update(is_delete=True):  # 受影响的行得大于0
            return APIResponse(1, '删除失败')
        return APIResponse(0, '删除成功')

posted @ 2019-11-16 21:32  张明岩  阅读(225)  评论(0编辑  收藏  举报