首页 > 其他分享 >drf(序列化练习、user表练习)

drf(序列化练习、user表练习)

时间:2023-10-10 11:15:51浏览次数:30  
标签:name models True self 练习 user pk 序列化 data

一. APIView版本

1. models.py

from django.db import models


# Create your models here.

class CommonField(models.Model):
    is_delete = models.BooleanField(default=0, verbose_name='True标记被删除的数据,False标记正常使用的数据')
    create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    update_time = models.DateTimeField(auto_now=True, verbose_name='最后更新时间')

    class Meta:
        """
        参数拓展:
        db_table: 指定字符串. 用来修改表名
        abstract: 指定布尔值. 用来建立抽象表, 该表不会在数据库中创建
        unique_together: 指定容器. 用来建立多字段唯一
        index_together:  指定容器. 用来建立多字段之间的联合索引
        单个字段,有索引,有唯一
        多个字段,有联合索引,联合唯一
        verbose_name: 指定字符串. 用来admin中显示表名, 默认加后缀s.
        verbose_name_plural: 指定字符串. 用来admin中显示表名, 默认不加后缀s.
        """
        abstract = True  # 指定布尔值. 用来建立抽象表, 该表不会在数据库中创建


class Book(CommonField):
    """
    参数拓展:
        blank:  指定布尔值. 用来表示admin后台管理该字段时候可以为空.
        help_text: 指定字符串. 用来表示admin后台管理的提示信息.

    外键关联:
        to_field: 指定关联的表的外键字段. 默认不写,关联到关联表的主键值.
        db_constraint:  逻辑上的关联,实质上没有外键练习,增删不会受外键影响,以及不影响orm查询.
        ForeignKey 与 OneToOneField
            由源码得知OneToOneField继承ForeignKey, 并且默认制定了unique=True参数
            ForeignKey(to='AuthorDetail', unique=True)
            OneToOneField(to='AuthorDetail')

    on_delete参数:
        1、表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
        2、断关联后不会影响数据库查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
        3、断关联一定要通过逻辑保证表之间数据的安全,不要出现脏数据,代码控制
        4、断关联
        5、级联关系
              作者没了,详情也没:on_delete=models.CASCADE
              出版社没了,书还是那个出版社出版:on_delete=models.DO_NOTHING
              部门没了,员工没有部门(空不能):null=True, on_delete=models.SET_NULL
              部门没了,员工进入默认部门(默认值):default=0, on_delete=models.SET_DEFAULT
    """
    title = models.CharField(max_length=32, verbose_name='书名')
    price = models.DecimalField(max_digits=4, decimal_places=2, verbose_name='价格')
    publish = models.ForeignKey(to='Publish', to_field='id', db_constraint=False, on_delete=models.DO_NOTHING)
    # 提示: to_field不能指定pk, 而是需要指定对应关联表的实际字段. 如果指定pk, 将会抛出如下异常:
    '''
    publish = models.ForeignKey(to='Publish', to_field='pk', on_delete=models.DO_NOTHING, db_constraint=False)
    ERRORS:
        api.Book.publish: (fields.E312) The to_field 'pk' doesn't exist on the related model 'api.Publish'.
    '''
    authors = models.ManyToManyField(to='Author', db_constraint=False)  # 有第三张表,没有on_delete参数
    # 什么时候需要半自动,主要看第三张变需要扩字段,比如要看第三张表的两个字段什么时候建立关系的,扩展一张时间表
    # 半自动表的创建db_constraint参数的存在就会抛出如下异常:
    '''
    TypeError: __init__() got an unexpected keyword argument 'db_contraint'
    '''

    # 半自动
    # authors = models.ManyToManyField(to='Author', through_fields=('book', 'author'), through='Author2Book', db_constraint=False)
    class Meta:
        verbose_name = '图书表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title

    @property  # 提示: property装饰器可以不指定
    def publish_name(self):
        return self.publish.name

    # @property   # 提示: property装饰器可以不指定
    def author_list(self):
        # lis = []
        # for author_obj in self.authors.all():  # 子查询正向,字段名,多个加all()
        #     lis.append({'name': author_obj.name, 'sex': author_obj.get_gender_display()})
        # return lis
        # 列表推导式
        return [{'name': author_obj.name, 'sex': author_obj.get_gender_display()} for author_obj in self.authors.all()]


# class Author2Book(models.Model):
#     author = models.ForeignKey(to='Author', on_delete=models.DO_NOTHING, db_constraint=False)
#     book = models.ForeignKey(to='Book', on_delete=models.NOT_PROVIDED, db_constraint=False)

class Publish(CommonField):
    name = models.CharField(max_length=32, verbose_name='出版社名')
    addr = models.CharField(max_length=64, verbose_name='地址')

    class Meta:
        verbose_name = '出版社表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Author(CommonField):
    name = models.CharField(max_length=32, verbose_name='作者名')
    gender_choice = (
        (0, '男'),
        (1, '女'),
        (2, '秘密')
    )
    gender = models.IntegerField(choices=gender_choice, default=2, verbose_name='作者性别')
    author_detail = models.OneToOneField(to='AuthorDetail', db_constraint=False, on_delete=models.CASCADE)

    class Meta:
        verbose_name = '作者表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class AuthorDetail(CommonField):
    phone = models.CharField(max_length=11, verbose_name='作者手机号')

    class Meta:
        verbose_name = '作者详情表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.phone

2. ser.py 自定义序列化.py文件

from rest_framework import serializers
from app01 import models


# many的设置后,重写update方法
class BookListSerializer(serializers.ListSerializer):
    # def create(self, validated_data):   # ListSerializer的create已帮写好了,不需要重写
    #     pass
    def update(self, instance, validated_data):
        return [self.child.update(instance[k], attrs) for k, attrs in enumerate(validated_data)]


# 提示: 序列化操作的是数据库的表,推荐使用ModelSerializer
class BookModelSerializer(serializers.ModelSerializer):
    # 第一种方式: 通过指定参数read_only=True, 在反序列化的时候不需要传该字段指定的值
    # publish_name = serializers.CharField(source='publish.name', read_only=True)  # 一对多关系,字段名
    # read_only解决反序列化的问题

    # 第二种方式: 在模型类中写方法, 通过方法关联到这里的字段. 如authors_list字段
    class Meta:
        """
        depth: 指定整数. 表示跨表查询的深度.
            如果指定2, 查询的时候就会将本实例中Book表关联的表, 以及关联表的关联的表所有的数据获取出来.
        """
        # 视图类中有many参数的,利用了元类的控制不同的类来生成对象,重写ListSerializer的方法,需要list_serializer_class = BookListSerializer
        list_serializer_class = BookListSerializer
        model = models.Book
        # fields = '__all__'
        # depth = 0
        fields = ('id', 'title', 'price', 'publish', 'publish_name', 'authors', 'author_list')
        extra_kwargs = {
            'publish': {'write_only': True},
            'publish_name': {'read_only': True},
            'authors': {'write_only': True},
            'author_list': {'read_only': True},
            'pk': {'read_only': True}
        }

3. views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from app01 import ser
from utils.exception import NonentityError

from utils.response import CommonResponse


# Create your views here.

class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        '''
        # 如何区分请求过来是获取单条还是多条数据?
            先配置2条路由, 2条路由都指向同一个视图类. 再通过url传递过来kwargs中是时候有pk值.
            有: 单条数据  没有: 多条数据
        # 前提: 所有的获取都需要在过滤is_delete=True的字段, 获取的只是没有标记被删除的is_delete=False的数据
        # 获取单条数据: 直接获取到数据对象, 再使用自定义的序列化类序列话数据. 拿到序列化之后的结果
        # 获取多条数据: 直接获取到queryset对象, 序列化时需要指定many=True, 即可
        '''
        # 获取一条
        pk = kwargs.get('pk')
        if pk:
            book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
            book_ser = ser.BookModelSerializer(book_obj)
        # 获取多条
        else:
            book_query = models.Book.objects.all().filter(is_delete=False)  # 筛选出为删除的
            book_ser = ser.BookModelSerializer(book_query, many=True)
        return CommonResponse(results=book_ser.data)
        # return Response({'code': 1000, 'msg': '成功', 'data': book_ser.data})

    def post(self, request, *args, **kwargs):
        '''
        # 如何区分请求过来是新增单条还是多条数据?
            在postman中的数据格式
            单条数据格式: {}
            多条数据格式: [{}, {}]
        # 新增单条数据 和 新增多条数据
            数据都是从body中获取, 反序列化时指定的参数是data, 还需要注意的就是多条数据需要指定many=True.
            提示: 新增多条数据, ListSerializer中定义了create方法
                本质就是通过for循环, 再调用ModelSerializer中的create方法.
                def create(self, validate_data):
                    # self.child就是当前视图中所指序列化类实例化得到的对象(BookModelSerializer对象)
                    return [self.child.create(attrs) for attrs in validate_data]
        '''
        # 新增一条
        if isinstance(request.data, dict):
            book_ser = ser.BookModelSerializer(data=request.data)  # 关键字参数传参
        # 新增多条
        elif isinstance(request.data, list):
            book_ser = ser.BookModelSerializer(data=request.data, many=True)  # 关键字参数传参,增多条
            # book_ser是ListSerializer对象,for循环后,就是单个新增
        else:
            raise NonentityError('Add data through lists or dictionaries!')
        book_ser.is_valid(raise_exception=True)
        book_ser.save()
        return CommonResponse(results=book_ser.data)

    def put(self, request, **kwargs):
        '''
        # 如何区分请求过来是修改单条还是多条数据?
            判断: 通过路由的又名分组, 到kwargs中时候能获取pk值来判断
            单条数据格式: pk -> {}
            多条数据格式: [{'pk': ... }, {'pk': ... }]
        # 修改单条数据
            先获取传递过来的pk, 过滤出需要修改的数据对象
            再往序列化的类中传递需要修改的对象, 以及该对象修改的数据

        # 修改多条数据
            先将传过来的列表套字典格式的数据中的所有字典中pk获取, 再使用双下划线过滤出对应的所有对象, 返回一个queryset对象.
            再往序列换的类很重传递需要修改的queryset对象, 以及传递过来的要修改成什么样子的数据, 注意: 需要指定many=True
            提示: 上面指定了many=True, 序列化完毕以后返回的是一个由ListSerializer类. ListSerializer类中定义了create,
                但是没办法书写update方法, 因此需要我们重写.
            步骤:
                1) 新建一个类, 继承ListSerializer
                2) 重写create方法
                    def create(self, instance, validate_data):
                        return [self.child.update(instance[i], attrs) for i, attrs in enumerate(validate_data)]
                3) 在当前视图中执行序化类中在其, Meta中声明处理many=True时的类. list_serializer_class = 新建类名
        '''
        # 修改一条
        pk = kwargs.get('pk')
        if pk:
            book_obj = models.Book.objects.filter(pk=pk).first()
            print(request.data)
            book_ser = ser.BookModelSerializer(instance=book_obj, data=request.data, partial=True)
            # partial=True,可以对部分字段进行上传修改,没有的话,就要整个表的字段进行上传
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return CommonResponse(results=book_ser.data)
        # 修改多条
        elif isinstance(request.data, list):
            # 第一种方案,request.data是列表套字典[{},{}],按id,生成[书对象1,书对象2],对应修改数据列表
            # for循环一个一个的修改
            book_obj_list = []
            modify_data = []
            for book_dic in request.data:
                pk = book_dic.get('id')
                book_obj_list.append(models.Book.objects.filter(pk=pk).first())
                modify_data.append(book_dic)
            # book_ser_list =[]
            # for k, v in enumerate(modify_data):
            #     book_ser = ser.BookModelSerializer(instance=book_obj_list[k], data=v)
            #     book_ser.is_valid(raise_exception=True)
            #     book_ser.save()
            #     book_ser_list.append(book_ser.data)
            # return CommonResponse(results=book_ser_list)
            # 第二种方案,重写ListSerializer的update方法
            book_ser = ser.BookModelSerializer(instance=book_obj_list, data=modify_data, many=True)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return CommonResponse(results=book_ser.data)
        else:
            raise NonentityError('Specifies that the keyword can be partially modified or that the dictionary \
                format of the list can be modified multiple times!')

    def delete(self, request, *args, **kwargs):
        '''
        # 如何区分请求过来是修改单条还是多条数据?
            单条数据: 判断kwargs中是否有pk值
            多条数据: {'pks': [1, 2, 3]}
        # 删除单个 和 删除多个数据
            提示: 不是真正的删除, 而是修改对应数据中的is_delete字段等于True
            删除单个可
        '''
        pk = kwargs.get('pk')
        pks = []
        if pk:
            # 单条删除
            pks.append(pk)
        # 不管单条删除还是多条删除,都是按照多条删除的方式来
        # 多条删除
        # 前端传过来的格式是{'pks':[1,2,3]}
        else:
            pks = request.data.get('pks')
        # 不是真的删除,只是把is_delete设置为True
        res = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
        # is_delete=False,把为删除的数据筛选出来
        print(res)
        if res:
            return CommonResponse(msg='删除成功')
        else:
            return CommonResponse(msg='没有要删除的数据')

4. urls.py

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookAPIView.as_view()),
    path('books/<int:pk>/', views.BookAPIView.as_view()),
    # 分页器
    path('books1/', views.BookListAPIView.as_view()),
    path('books2/', views.BookAPIView1.as_view()),
]

5. utils 自定义工具包

1) exception_handler.py 自定义异常处理

from rest_framework.views import exception_handler
from rest_framework import status
from .response import CommonResponse


def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if not response:
        obj = CommonResponse(code=2000, messages='失败', error=str(exc), results=str(context),
                            status=status.HTTP_403_FORBIDDEN)
    else:
        obj = CommonResponse(code=2001, messages='失败', error=str(response.data), results=str(context),
                            status=status.HTTP_403_FORBIDDEN)
    return obj

2) exception.py 自定义错误类型

class NonentityError(Exception):
    def __init__(self, value):
        self.value = value
        super().__init__()

    def __str__(self):
        return '< %s >' % self.value

3) response.py 自定义封装response对象

from rest_framework.response import Response


class CommonResponse(Response):
    def __init__(self, code=1000, msg='成功', results=None, error=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None, **kwargs):
        dic = {'code': code, 'msg': msg}
        if results:
            dic['results'] = results
        if error:
            dic['error'] = error
        dic.update(kwargs)
        super().__init__(data=dic, status=status, template_name=template_name, headers=headers, exception=exception,
                         content_type=content_type)

4) throttle.py 自定义频率校验

from rest_framework.throttling import SimpleRateThrottle


class CustomSimpleRateThrottle(SimpleRateThrottle):
    scope = 'custom'

    def get_cache_key(self, request, view):
        # 'REMOTE_ADDR': '127.0.0.1',
        # print(request.META.get('REMOTE_ADDR'))
        return request.META.get('REMOTE_ADDR')

6. 总结

# 设计模型表的总结
    1. 所有的表应该都有三个基本字段: is_delete, create_time, update_time
        因此新增一个类继承Model, 之后的所有的类表继承它即可.
        注意: 新增的类表默认会在执行数据库迁移命令以后, 会在数据库中生成,
            因此应该新建Meat类, 指定abstract=True抽象表, 这样它就不会生成该表了.
    2. 外键关联字段需要注意如下几种问题
        1) 一对一关系要建立在查询次数较多的一行
        2) 一对多关系要建立在多的一方, 如果建立在一的一行, 那么以后一的一行该外键对应的值将会是一个'[1, 2, 3]'这种结构.
            这不是我们想要的. 我们最起码应该满足数据的数据设计存储规范.
        3) 级联关系: 建立外键关联的字段要着重考虑on_delete参数.
            如果一方没了, 那么另一方应该没有. 那么使用models.CASCADE(提示: 一对一关系表, 一般都是指定这个参数)
            如果一方没了, 那么另一方应该存在. 那么使用models.DO_NOTHING
            如果一方没了, 那么另一行应该设置为空. 那么使用models.SET_NULL
            如果一方没了, 那么另一行应该转移到设置的默认情况上. 那么使用models.SET_DEFAULT
        4) 断关联: 建立外键关联的字段最好使用db_constraint=False.
            使用它可以提升对数据的操作, 不用依照外键之间删除数据, 新增数据的限制, 就可以直接对数据进行操作,
            使用这种名义上的关联能最大化的提升数据库增删改的效率.
            缺点: 如果直接操作数据库会出现脏数据, 因此不要直接操作数据库, 代码层面对数据的操作, 可以进行有效的控制即可
    3. 疑问: 为什么创建半自动表使用db_constraint=False就会出现问题???

# 序列化器实现总结
    1. 序列化操作涉及到数据库的操作, 推荐使用ModelSerializer
    2. depth: 指定整数. 表示跨表查询的深度.  提示: 一般都不深度查询
    3. 重点: 关于外键关联, 序列化 与 反序列化 是有所不同的
        1) 专门用与序列化的字段设计:   新建一个外键字段指定只读
            2种方法:
                第一种: 序列化器中使用source
                第二种: 模型类中写方法, 在fields中声明
            注意: 该字段只读, 可在extra_kwargs中声明
        2) 专门用与反序列化的字段设计: 默认的外键字段指定只写.


# 视图方法实现总结
    # get
        # 如何区分请求过来是获取单条还是多条数据?
            先配置2条路由, 2条路由都指向同一个视图类. 再通过url传递过来kwargs中是时候有pk值.
            有: 单条数据  没有: 多条数据
        # 前提: 所有的获取都需要在过滤is_delete=True的字段, 获取的只是没有标记被删除的is_delete=False的数据
        # 获取单条数据: 直接获取到数据对象, 再使用自定义的序列化类序列话数据. 拿到序列化之后的结果
        # 获取多条数据: 直接获取到queryset对象, 序列化时需要指定many=True, 即可

    # post
        # 如何区分请求过来是新增单条还是多条数据?
            单条数据格式: {}
            多条数据格式: [{}, {}]
        # 新增单条数据 和 新增多条数据
            数据都是从body中获取, 反序列化时指定的参数是data, 还需要注意的就是多条数据需要指定many=True.
            提示: 新增多条数据, ListSerializer中定义了create方法
                本质就是通过for循环, 再调用ModelSerializer中的create方法.
                def create(self, validate_data):
                    # self.child就是当前视图中指行序列化类实例化得到的对象
                    return [self.child.create(attrs) for attrs in validate_data]

    # put
        # 如何区分请求过来是修改单条还是多条数据?
            判断: 通过路由的又名分组, 到kwargs中时候能获取pk值来判断
            单条数据格式: pk -> {}
            多条数据格式: [{'pk': ... }, {'pk': ... }]
        # 修改单条数据
            先获取传递过来的pk, 过滤出需要修改的数据对象
            再往序列化的类中传递需要修改的对象, 以及该对象修改的数据

        # 修改多条数据
            先将传过来的列表套字典格式的数据中的所有字典中pk获取, 再使用双下划线过滤出对应的所有对象, 返回一个queryset对象.
            再往序列换的类很重传递需要修改的queryset对象, 以及传递过来的要修改成什么样子的数据, 注意: 需要指定many=True
            提示: 上面指定了many=True, 序列化完毕以后返回的是一个由ListSerializer类. ListSerializer类中定义了create,
                但是没办法书写update方法, 因此需要我们重写.
            步骤:
                1) 新建一个类, 继承ListSerializer
                2) 重写create方法
                    def create(self, instance, validate_data):
                        return [self.child.update(instance[i], attrs) for i, attrs in enumerate(validate_data)]
                3) 在当前视图中执行序化类中在其, Meta中声明处理many=True时的类. list_serializer_class = 新建类名

    # delete
        # 如何区分请求过来是修改单条还是多条数据?
            单条数据: 判断kwargs中是否有pk值
            多条数据: {'pks': [1, 2, 3]}
        # 删除单个 和 删除多个数据
            提示: 不是真正的删除, 而是修改对应数据中的is_delete字段等于True
            删除单个可

二. GenericAPIView版本

from rest_framework.generics import GenericAPIView
from . import models
from . import ser
from utils.response import CommonResponse
from utils.exception import NonentityError


class BookAPIView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = ser.BookModelSerializer

    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            instance = self.get_object()
            # is_delete=True表示数据是做了删除标记的
            if instance.is_delete:
                raise NonentityError('The data as well does not exist anymore!')
            else:
                serializer = self.get_serializer(instance=instance)
        else:
            instance = self.get_queryset().filter(is_delete=False)
            serializer = self.get_serializer(instance=instance, many=True)
        return CommonResponse(results=serializer.data)

    def post(self, request, *args, **kwargs):
        if isinstance(request.data, list):
            serializer = self.get_serializer(data=request.data, many=True)
        elif isinstance(request.data, dict):
            serializer = self.get_serializer(data=request.data)
        else:
            raise NonentityError('Add data through lists or dictionaries!')
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return CommonResponse(results=serializer.data)

    def put(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            instance = self.get_object()
            serializer = self.get_serializer(instance=instance, data=request.data, partial=True)
        elif isinstance(request.data, list):
            # request.data = [{'id': 1, 'name': 'xxx', 'price': 'xxx'}]
            pks = [dic.get('id') for dic in request.data]
            instance = self.get_queryset().filter(pk__in=pks)
            serializer = self.get_serializer(instance=instance, data=request.data, many=True)
        else:
            raise NonentityError(
                'Specifies that the keyword can be partially modified or that the dictionary \
                format of the list can be modified multiple times!')
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return CommonResponse(results=serializer.data)

    def delete(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        pks = []
        pks = pks.append(pk) if pk else request.date.get('pks')
        affected_rows = self.get_queryset().filter(pk__in=pks).update(is_delete=True)
        return CommonResponse(results={'affected_rows': affected_rows})

总结

主要要明白GenericAPIView中提供的三种主要的方法的返回值
self.get_object()      返回数据对象
self.get_queryset()    返回queryset对象. 因此这里就可以继续有filter(), update()等连点操作
self.get_serializer()  many=

三、user表练习

作业讲解

1 自定义user表,新增phone唯一约束字段,新增icon图片字段

2 在自定义user表基础上,用GenericViewSet + CreateModelMixin + serializer,完成user表新增接口(就是注册接口)(重要提示:序列化类要重写create方法,不然密码就是明文)

3 在自定义user表基础上,用GenericViewSet + RetrieveModelMixin + serializer 完成user表单查(就是用户中心)

4 在自定义user表基础上,用GenericViewSet + UpdateModelMixin + serializer 完成头像的修改

models.py

from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.

class UserInfo(AbstractUser):
    phone = models.CharField(max_length=11, unique=True)  # 唯一
    icon = models.ImageField(upload_to='icon', default='icon/default.png')  # ImageField依赖于pillow模块


class Book(models.Model):
    name = models.CharField(max_length=64)

    def __str__(self):
        return self.name


class Car(models.Model):
    name = models.CharField(max_length=64)

    def __str__(self):
        return self.name

view.py

# 作业讲解
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, UpdateModelMixin
from app01 import models
from app01 import ser


class RegisterView(GenericViewSet, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin):
    queryset = models.UserInfo.objects.all()
    serializer_class = ser.UserModelSerializer

    '''
    假设get请求和post请求,用的序列化类不一样,如何处理?
    重写get_serializer_class,返回啥,用的序列化类就是啥
    注册,用的序列化类是UserModelSerializer,查询一个用的序列化类是UserReadOnlySerializer
    '''

    def get_serializer_class(self):
        if self.action == 'create':
            return ser.UserModelSerializer
        elif self.action == 'retrieve':
            return ser.UserReadOnlySerializer
        elif self.action == 'update':
            return ser.UserImageViewSerializer

ser.py

from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models


class UserModelSerializer(serializers.ModelSerializer):
    re_password = serializers.CharField(max_length=11, required=True, write_only=True)  # 因为re_password在表中没有,需要在这里定义

    class Meta:
        model = models.UserInfo
        fields = ['username', 'password', 'phone', 're_password', 'icon']
        extra_kwargs = {
            'username': {'max_length': 16},
            'password': {'write_only': True}
        }

    # 局部钩子
    def validate_phone(self, data):
        if not len(data) == 11:
            raise ValidationError('手机号是11位')
        return data

    # 全局钩子
    def validate(self, attrs):
        if not attrs.get('password') == attrs.get('re_password'):
            raise ValidationError('两次密码不一致')
        attrs.pop('re_password')
        return attrs

    # 重写新增方法
    def create(self, validated_data):
        # models.UserInfo.objects.create(**validated_data)    # 密码是明文,所以要重写create方法
        user_obj = models.UserInfo.objects.create_user(**validated_data)
        return user_obj


class UserReadOnlySerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = ['username', 'icon']


class UserImageViewSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = ['icon', ]

 

标签:name,models,True,self,练习,user,pk,序列化,data
From: https://www.cnblogs.com/coderxueshan/p/17754120.html

相关文章

  • 练习记录-cf-Educational Codeforces Round 156 (Rated for Div. 2)(A-C)
    好久没打了还是就出了三道不过还好没掉分A.SumofThree就是问能不能把一个数拆成三个不同的且都不能被三整除的数我的思路就是拆成1+2+一个大于等于4的数如果拆了后另一个数是%3==0那么我拆成1+4它肯定就不被整除然后判下相同#include<bits/stdc++.h>#defineclose......
  • python练习题(一)
    算法题1.计算1-100之间所有偶数的和#定义一个变量用来保存最后的累加和total_even_sum=0#从1到100的数fornuminrange(1,101):#判断是否为偶数ifnum%2==0:total_even_sum+=numprint("偶数和是:",total_even_sum)2.计算1-100的和#......
  • python练习题(二)
    文件操作1.读取一个文本文件,打印文件内容到控制台。defprint_file_content(file_path):try:withopen(file_path,'r')asfile:content=file.read()print(content)exceptExceptionase:print(f"没有找到文件:{e}"......
  • 博弈论——练习(十三)
    1(分钱)两人之间分\(10\)。使用下述方法:每个人说出一个至多为10的数字(非负整数)。如果两人说出的数字之和不超过10,那么每个人得到她所说出的钱数(多出的钱被销毁),如果两人提出的数字之和超过10并且数目不同,那么说出较小数的人得到自己所说的钱数,而另一个人则得到剩余的钱。如果......
  • npm WARN saveError ENOENT: no such file or directory, open 'C:\Users\Administr
     C:\Users\Administrator>npminstallaxiosnpmWARNsaveErrorENOENT:nosuchfileordirectory,open'C:\Users\Administrator\package.json'npmnoticecreatedalockfileaspackage-lock.json.Youshouldcommitthisfile.npmWARNenoentE......
  • Unity 通信方案 - 使用 Google Protobuf 序列化数据
    1.下载和编译1.1下载ProtoBuf源文件从github下载最新的protoBuf库,如下图所示 Releases·protocolbuffers/protobuf(github.com)1.2编译dll和导入解压后打开/scharp/src中的sln工程文件 选择Release,Google.Protobuf,之后在生成中生成文件在......
  • 建表,和练习题
    目录建库注意::整形和浮点型不用加''号,其他字符串型那部分需要加''表一联合主键001建表练习题查询练习sql练习建库createdatabaselinux注意::整形和浮点型不用加''号,其他字符串型那部分需要加''表一字段数据类型要求是否为空注释sno最多20位否学号(主键)sn......
  • 课堂练习
    目录pod的资源限制手动更改cpu等资源的最大最小值#命令更改[root@master-1rc]#kubectlscalersnginx-rs--replicas=8#文件内容更改,不用重启[root@master-1rc]#kubectleditrsnginx-rs#直接更改资源文件,要从新启动vimrs.yaml#rs实时扩缩容量#podapiVers......
  • c语言代码练习(与“&”)26
    需求:求一个整数存储在内存中二进制中的1的数量#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>intmain(){intnum=0;intinput=0;printf("请输入你想要统计的数字:");scanf("%d",&input);inti=0;for(i=0;i<32;i+......
  • oj练习题 数字 eval 整数 int ???
      s=input()if'helloworld!'==s.casefold():print("Yes")else:print("No")    A+B问题II描述亲爱的小朋友们,大家好!今天我们来探讨一下大家都会做的A+B的问题,给你两个数A和B,请你输出这两个数的和。输入输入两个数字,a和b输出输出一个......