• ModelSerializer 序列化和反序列化,及序列化整合,单删/增,群删/增(delete请求)


    ModelSerializer 序列化
    序列化准备

    - 模型层:models.py
    from django.db import models

    # 1.基表模型类的封装(建立公有字段)
    class BaseModel(models.Model):
        is_delete = models.BooleanField(default=False)
        create_time = models.DateTimeField(auto_now_add=True)  # 创建的时候更新时间
    
        # 作为基表的model一定要加上,迁移命令之后不会在数据库中生成表
        class Meta:
            abstract = True
    
    
    class Book(BaseModel):
        name = models.CharField(max_length=64)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        img = models.ImageField(upload_to='img', default='img/default.jpg')
        publish = models.ForeignKey(to="Publish",
                                    db_constraint=False,
                                    related_name="books",
                                    on_delete=models.DO_NOTHING
                                    )
        authors = models.ManyToManyField(to="Author",
                                         db_constraint=False,
                                         related_name='books',
                                         )
    
        def fn(self):
            return 'fn fn fn '
    
        # 序列化插拔式属性 - 完成自定义字段名完成连表查询
        @property
        def publish_name(self):
            return self.publish.name
    
        @property
        def author_list(self):
            return self.authors.values('name', 'age', 'detail__mobile').all()
    
        class Meta:
            db_table = 'book'
            verbose_name = '书籍表'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class Publish(BaseModel):
        name = models.CharField(max_length=64)
        address = models.CharField(max_length=64)
    
        class Meta:
            db_table = 'publish'
            verbose_name = '出版社'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class Author(BaseModel):
        name = models.CharField(max_length=64)
        age = models.IntegerField()
    
        class Meta:
            db_table = 'author'
            verbose_name = '作者表'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class AuthorDetail(BaseModel):
        mobile = models.CharField(max_length=11)
        author = models.OneToOneField(to="Author",
                                      db_constraint=False,
                                      on_delete=models.CASCADE,
                                      related_name='detail'
                                      )
        db_constraint=False断关联
        # 1.作者删除,详情也跟着删除  - on-delete = models.CASCADE
        # 2.作者删除,详情置空 - null =True ,on-delete = models.SET_NULL
        # 3.作者删除,详情重置  default=0,on_delete = models.SET_DEFAULT
        # 4.作者删除,详情不动 on_delete = models.DD_NOTHING
        class Meta:
            db_table = 'authorDetail'
            verbose_name = '作者详情'
            verbose_name_plural = verbose_name

    db_constraint=False断关联
    """
    1、外键位置:
       一对多 - 外键放多的一方
       一对一 - 从逻辑正反向考虑,如作者表与作者详情表,作者删除级联删除详情,详情删除作者依旧存在,所以建议外键在详情表中
       多对多 - 外键在关系表中
    
    2、ORM正向方向连表查找:
       正向:通过外键字段 eg: author_detial_obj.author
       反向:通过related_name的值 eg:author_obj.detail
       注:依赖代码见下方
    
    3、连表操作关系:
       1)作者删除,详情级联 - on_delete=models.CASCADE
       2)作者删除,详情置空 - null=True, on_delete=models.SET_NULL
       3)作者删除,详情重置 - default=0, on_delete=models.SET_DEFAULT
       4)作者删除,详情不动 - on_delete=models.DO_NOTHING
       注:拿作者与作者详情表举例
    
    4、外键关联字段的参数 - 如何实现 断关联、目前表间操作关系、方向查询字段
       i)作者详情表中的
       author = models.OneToOneField(
          to='Author',
            related_name='detail',
            db_constraint=False,
            on_delete=models.CASCADE
        )
    
        ii)图书表中的
        publish = models.ForeignKey(
           to='Publish',
            related_name='books',
            db_constraint=False,
            on_delete=models.DO_NOTHING,
        )
        authors = models.ManyToManyField(
           to='Author'
            related_name='books',
            db_constraint=False,
        )
        注:ManyToManyField不能设置on_delete,OneToOneField、ForeignKey必须设置on_delete(django1.x系统默认级联,但是django2.x必须手动明确)
    """

    - 后台管理层:admin.py

    ```注册
    from django.contrib import admin
    from . import models
    
    admin.site.register(models.User)  # 只要需要后台操作都要注册

    - 配置层:settings.py

    # 注册rest_framework
    INSTALLED_APPS = [
        # ...
        'rest_framework',
    ]

    # media资源
    MEDIA_URL = '/media/' # 后期高级序列化类与视图类,会使用该配置
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # media资源路径

    # 国际化配置
    LANGUAGE_CODE = 'zh-hans'
    TIME_ZONE = 'Asia/Shanghai'
    USE_I18N = True
    USE_L10N = True
    USE_TZ = False

    #### 序列化使用
    ##在api中建立一个serializers.py文件夹


    - 序列化层:api/serializers.py
    from rest_framework.serializers import ModelSerializer, SerializerMethodField
    
    from . import models
    
    class PublishModelSerializer(ModelSerializer):
        class Meta:
            model = models.Publish
            fields = '__all__'
    
    # 序列化发送数据给前端
    class BookModelSerializer(ModelSerializer):
        # 了解,这样的字段规定了必须查找在fileds中申明,否则报错
        # publish_address = SerializerMethodField()
        #
        # def get_publish_address(self, obj):
        #     return obj.publish.address
    
        # 自定义连表深度 - 子序列化方式,定义之后必须在fields注册,否则报错
        publish = PublishModelSerializer()
    
        class Meta:
            # 序列化关联的model类
            model = models.Book
    
            # 参与序列化的字段
            fields = ('name', 'price', 'img', 'publish_name', 'author_list','publish')
            # fields ='__all__'  # 显示所有字段
    
            # exclude = ("id", "is_delete", "create_time")  # 除开哪些字段
            # 自动连表深度
            # depth =1
    # 视图层(views)
    class Book(APIView):
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                try:
                    book_obj = models.Book.objects.get(pk=pk,is_delete=False)
                    book_data = serializers.BookModelSerializer(book_obj).data
                except:
                    return Response({
                        'status': 1,
                        "msg": '书籍不存在',
                    })
            else:
                book_query = models.Book.objects.filter(is_delete=False).all()
                book_data = serializers.BookModelSerializer(book_query,many=True).data
            return Response({
                'status': 0,
                "msg": '访问成功',
                "results": book_data
            })

    ## 反序列化

    ##### 序列化层:api/serializers.py

    class BookModelDeserializer(ModelSerializer):
        class Meta:
            model = models.Book
            fields = ('name', 'price', 'publish', 'authors')  
            # extra_kwargs 用来完成反序列化字段的 系统校验规则 “required:True 必须校验
            extra_kwargs = {
                'name': {
                    'required': True,
                    'min_length': 1,
                    'error_messages': {
                        'required': '必填项',
                        'min_length': '太短',
                    }
                }
            }
    
        # 局部钩子
        def validate_name(self, value):
            # 书名不能包含 g 字符
            if 'g' in value.lower():
                raise ValidationError('该g书不能出版')
            return value
       # 全局钩子
        def validate(self, attrs):
            publish = attrs.get('publish')
            name = attrs.get('name')
            if models.Book.objects.filter(name=name, publish=publish):
                raise ValidationError({'book': '该书已存在'})
            return attrs
    
        # ModelSerializer类已经帮我们实现了 create 与 update 方法
    
    ```

    ##### 视图层:api/views.py

    class Book(APIView):
        def post(self, request, *args, **kwargs):
            request_data = request.data
            book_ser = serializers.BookModelDeserializer(data=request_data)
            # raise_exception=True:当校验失败,马上终止当前视图方法,抛异常返回给前台
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.BookModelSerializer(book_obj).data
            })
    ```

    ##### 路由层:api/urls.py

    urlpatterns = [
        url(r'^books/$', views.Book.as_view()),
        url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
    ]
    ```

    ## 序列化与反序列化整合(重点)

    ##### 序列化层:api/serializers.py

    1) fields中设置所有序列化与反序列化字段
    2) extra_kwargs划分只序列化或只反序列化字段
        write_only:只反序列化
        read_only:只序列化
        自定义字段默认只序列化(read_only)
    3) 设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则
    
    
    class V2BookModelSerializer(ModelSerializer):
        class Meta:
            model = models.Book
            fields = ('name', 'price', 'img', 'author_list', 'publish_name', 'publish', 'authors')
            extra_kwargs = {
                'name': {
                    'required': True,
                    'min_length': 1,
                    'error_messages': {
                        'required': '必填项',
                        'min_length': '太短',
                    }
                },
                'publish': {
                    'write_only': True
                },
                'authors': {
                    'write_only': True
                },
                'img': {
                    'read_only': True,
                },
                'author_list': {
                    'read_only': True,
                },
                'publish_name': {
                    'read_only': True,
                }
            }
    
        def validate_name(self, value):
            # 书名不能包含 g 字符
            if 'g' in value.lower():
                raise ValidationError('该g书不能出版')
            return value
    
        def validate(self, attrs):
            publish = attrs.get('publish')
            name = attrs.get('name')
            if models.Book.objects.filter(name=name, publish=publish):
                raise ValidationError({'book': '该书已存在'})
            return attrs
    ```

    ##### 视图层:api/views.py

    class V2Book(APIView):
        # 单查:有pk
        # 群查:无pk
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                try:
                    book_obj = models.Book.objects.get(pk=pk, is_delete=False)
                    book_data = serializers.V2BookModelSerializer(book_obj).data
                except:
                    return Response({
                        'status': 1,
                        'msg': '书籍不存在'
                    })
            else:
                book_query = models.Book.objects.filter(is_delete=False).all()
                book_data = serializers.V2BookModelSerializer(book_query, many=True).data
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': book_data
            })
    
        # 单增:传的数据是与model对应的字典
        # 群增:传的数据是 装多个 model对应字典 的列表
        def post(self, request, *args, **kwargs):
            request_data = request.data
            if isinstance(request_data, dict):
                many = False
            elif isinstance(request_data, list):
                many = True
            else:
                return Response({
                    'status': 1,
                    'msg': '数据有误',
                })
            book_ser = serializers.V2BookModelSerializer(data=request_data, many=many)
            # 当校验失败,马上终止当前视图方法,抛异常返回给前台
            book_ser.is_valid(raise_exception=True)
            book_result = book_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.V2BookModelSerializer(book_result, many=many).data
            })
    
        # 单删:有pk
        # 群删:有pks   |  {"pks": [1, 2, 3]}
        def delete(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                pks = [pk]
            else:
                pks = request.data.get('pks')
            if models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True):
                return Response({
                    'status': 0,
                    'msg': '删除成功',
                })
            return Response({
                'status': 1,
                'msg': '删除失败',
            })
    ```

    ##### 路由层:api/urls.py


    urlpatterns = [
    url(r'^v2/books/$', views.V2Book.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.V2Book.as_view()),
    ]
    ```
  • 相关阅读:
    记一次线上Kafka消息堆积踩坑总结
    golang Time to String
    转MongoDB 使用Skip和limit分页
    golang mongodb (mgo)插入或读取文档的字段值为空(nil)问题解决
    Golang 中操作 Mongo Update 的方法
    基础知识
    Linux安全之SSH 密钥创建及密钥登录
    ssh配置authorized_keys后仍然需要输入密码的问题
    SSH隧道技术----端口转发,socket代理
    社会信息化环境下的IT新战略
  • 原文地址:https://www.cnblogs.com/wukai66/p/11703576.html
Copyright © 2020-2023  润新知