day03 序列化器-Serializer与ModelSerializer


day03 序列化器-Serializer与ModelSerializer

今日内容

  • 序列化器-Serializer
  • 序列化器的序列化
  • 序列化器的反序列化
  • 模型类序列化器ModelSerializer
  • django配置文件详解

1、序列化器-Serializer

# 序列化器的作用
1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能

2、序列化器的序列化

2.1 基本使用:写出5个接口

# 针对于某个表模型,总共5个接口
    获取所有  get
    获取单个  get
    删除单个  delete
    修改单个  update
    新增单个  post

# 以后你写的所有接口(跟数据库相关),都是这个5个或这5个的变形

2.11 models.py

from django.db import models
# 创建表
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.IntegerField()
    publish = models.CharField(max_length=32)

2.12 serializer.py

from rest_framework import serializers
from app01.models import Book


# 写序列化类
class BookSerializer(serializers.Serializer):
    title = serializers.CharField()
    price = serializers.IntegerField()
    publish = serializers.CharField()

    # 重写create,使它能够支持新增保存(派生)
    def create(self, validated_data):  # 校验后的数据
        book = Book.objects.create(**validated_data)
        return book  # 返回book

    # 重写update,使它能够支持修改(派生)
    def update(self, instance, validated_data):
        instance.title = validated_data.get('title')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()  # 修改后保存
        return instance
'''
总结:
	使用序列化器类,需要重写新增和修改
'''

2.13 views.py

from django.shortcuts import render

# 查询所有图书的视图类
from rest_framework.views import APIView
from app01.models import Book
from app01.serializer import BookSerializer
from rest_framework.response import Response


class BookView(APIView):
    # 查询所有接口
    def get(self, request, *args, **kwargs):
        # 查询出所有图书
        books = Book.objects.all()
        # 把qs对象序列化成字典,使用序列化类完成序列化
        # instance=None,   是要序列化的对象(可以是单个对象,可以是多个对象(放到列表或者qs对象),一定要写many=True)
        # data=empty       反序列化的字典,目前还没用到
        ser = BookSerializer(instance=books, many=True)  # 传入要序列化的数据
        # 返回给前端  ser.data 是个字典
        # 如果是浏览器,会有一个好看的页面(注册app),如果是postman,就是json格式
        return Response(ser.data)

    # 新增接口
    def post(self, request, *args, **kwargs):
        # 使用序列化类做保存
        ser = BookSerializer(data=request.data)
        # 数据校验:如果是True,表示校验通过,直接保存
        if ser.is_valid():
            ser.save()  # 调用保存,但是有问题,保存不了,一定要在序列化类中重写某个方法
            return Response(ser.data)
        else:
            return Response(ser.errors)


class BookDetailView(APIView):
    # 查询单个接口
    def get(self, request, pk):
        # 查询单本图书
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books)  # 序列化类中传入要序列化的数据
        return Response(ser.data)

    # 删除接口
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response()

    # 修改接口
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        # 数据校验:如果是True,表示校验通过,直接保存
        if ser.is_valid():
            ser.save()  # 调用保存,但是有问题,保存不了,一定要在序列化类中重写update方法
            return Response(ser.data)
        else:
            return Response(ser.errors)
'''
总结:
	因为删除和修改都需要用到主键值,所以写到转换器类中
'''

2.13 urls.py

from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    # 使用序列化转换器
    path('books//', views.BookDetailView.as_view()),
]

2.2 常用字段

AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型

2.3 常用字段参数

#参数名称	作用
max_length	最大长度
min_lenght	最小长度


allow_blank	是否允许为空
trim_whitespace	是否截断空白字符

max_value	最小值
min_value	最大值


#通用参数:(针对所有字段)

参数名称	说明
#非常重要
read_only	表明该字段仅用于序列化输出,默认False
write_only	表明该字段仅用于反序列化输入,默认False



required	表明该字段在反序列化时必须输入,默认True
default	反序列化时使用的默认值
allow_null	表明该字段是否允许传入None,默认False
validators	该字段使用的验证器
error_messages	包含错误编号与错误信息的字典

3、序列化器的反序列化

3.1 基本使用

# 反序列化与序列化
	序列化是从里面往外查询出数据
    反序列化是从外面进数据

# 可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.
# 可以通过实现create()和update()两个方法来实现。

from rest_framework.views import APIView
from app01.models import Book
from app01.serializer import BookSerializer
from rest_framework.response import Response

class BookView(APIView):
    # 新增
    def post(self, request, *args, **kwargs):
        # 使用序列化类做保存
        ser = BookSerializer(data=request.data)
        # 数据校验:如果是True,表示校验通过,直接保存
        if ser.is_valid():
            ser.save()  # 调用保存,但是有问题,保存不了,一定要在序列化类中重写某个方法
            return Response(ser.data)
        else:
            return Response(ser.errors)
        
class BookDetailView(APIView):
    # 修改接口
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        # 数据校验:如果是True,表示校验通过,直接保存
        if ser.is_valid():
            ser.save()  # 调用保存,但是有问题,保存不了,一定要在序列化类中重写update方法
            return Response(ser.data)
        else:
            return Response(ser.errors)
'''
总结:
	只有新增端口和修改端口是反序列化操作
'''

3.2 校验数据

from rest_framework import serializers
from app01.models import Book
from rest_framework.exceptions import ValidationError  # 异常模块


# 写序列化类
class BookSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=8, min_length=3)  # 校验字段
    price = serializers.IntegerField()
    publish = serializers.CharField()

    # 局部钩子,先走字段再走局部钩子
    def validate_title(self, item):  # validate + 字段名
        print(item)
        if item.startswith('sb'):
            raise ValidationError('不能以sb开头')
        return item

    # 全局钩子,先走字段再走局部钩子,最后在走全局钩子
    def validate(self, attrs):
        # 校验失败抛异常
        if attrs.get('title') == attrs.get('publish'):
            raise ValidationError('标题和出版社不能一样')
        return attrs

4、模型类序列化器ModelSerializer

4.1 基本使用

4.1.1 serializer.py

# 反序列化,正常情况不需要重写 create和update
# 序列化:跟表模型有对应关系,不需要一个个字段都写了

class BookModelSerializer(serializers.ModelSerializer):
    # 跟某个表模型建立关系
    class Meta:
        model = Book  # 跟哪个表建立关系
        fields = ['title', 'price', 'id', 'publish']  # 指定要序列化的类
        # fields = '__all__'  # 所有字段都序列化

    # 重写字段
    title = serializers.CharField(max_length=8, min_length=3)

    # 局部钩子:必须和class Meta平级
    def validate_price(self, price):
        if not price > 100:
            raise ValidationError('价格必须大于100')
        return price

'''第一种方法'''
class BookModelSerializer(serializers.ModelSerializer):
    # 跟某个表模型建立关系
    class Meta:
        model = Book  # 跟哪个表建立关系
        fields = ['title', 'price', 'id', 'publish']  # 指定要序列化的类

    # 重写字段
    title = serializers.CharField(max_length=8, min_length=3)  # 第一种方式,在外面
    
        # 第二种方式:是在class Meta里面
        extra_kwargs = { 
            'title': {'max_length': 8, 'min_length': 3},
            'price': {'min_value': 100}}


'''第二种方法'''
class BookModelSerializer(serializers.ModelSerializer):
    # 跟某个表模型建立关系
    class Meta:
        model = Book  # 跟哪个表建立关系
        fields = ['title', 'price', 'id', 'publish']  # 指定要序列化的类

        '''
        默认是:既做序列化又做反序列化
        read_only:只读,只序列化
        write_only:只写,只做序列化,这个字段不做系列化
        '''
        extra_kwargs = {
            'title': {'read_only': True},  # 只能做读操作,不能做写操作
            # 'price': {'min_value': 100}  # 只能做写操作,不能做读操作
        }

'''
作用:有些窗口给别人开放只能查看的接口,但是修改或者别的不能开放给别人
为什么ModelSerializer不用重写create()和update()方法呢?
因为ModelSerializer里面自己写了create()和update()方法。
'''

4.1.2 views.py

from app01.serializer import BookModelSerializer
class BookView(APIView):
    # 查询所有接口
    def get(self, request, *args, **kwargs):
        # 查询出所有图书
        books = Book.objects.all()
        ser = BookModelSerializer(instance=books, many=True)  # 传入要序列化的数据
        return Response(ser.data)

    # 新增接口
    def post(self, request, *args, **kwargs):
        ser = BookModelSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)


class BookDetailView(APIView):
    def get(self, request, pk):
        # 查询单本图书
        books = Book.objects.filter(pk=pk).first()
        ser = BookModelSerializer(instance=books)  # 序列化类中传入要序列化的数据
        return Response(ser.data)

    # 删除接口
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response()

    # 修改接口
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookModelSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)

4.2 常用方法

# 重点
    read_only:只读,只序列化
    write_only:只写,只做序列化,这个字段不做系列化
	fields = '__all__'  # 所有字段都序列化
        
# 了解
    exclude = ['title']  # 除了这个字段,别的都需要序列化
    depth = 1  # 表关联   

5、django配置文件详解

# django项目启动之前,先执行这个配置文件(加载配置文件)
# 如果配置文件出错,整个项目启动不起来
import os

# 项目根路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# 秘钥:django中涉及到加密的通常用整个密码
SECRET_KEY = '@m*wf@^=)_hfd5mw)m8j@3mw%c35dalm*luvf8ag@x-l7+7gm*'

# 项目是调试模式:1是报错显示在网页上,2是可以热加载(热更新)
DEBUG = True

# 后期项目上线,需要配置服务器的地址
ALLOWED_HOSTS = []

# Application definition
# 注册app的地址
INSTALLED_APPS = [
    'django.contrib.admin',  # 后台管理
    'django.contrib.auth',  # 认证 auth组件 用户表
    'django.contrib.contenttypes',  # 每创建一个表,都会有一个记录
    'django.contrib.sessions',  # session的使用
    'django.contrib.messages',  # 消息框架:在不同的请求之间传递数据
    'django.contrib.staticfiles',  # 静态文件
    'app01.apps.App01Config',  # 自己写的app
]

# 中间件
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',  # 认证相关的中间件
    'django.contrib.sessions.middleware.SessionMiddleware',  # session放入中间件
    'django.middleware.common.CommonMiddleware',  # 访问路径带不带斜杠 /
    'django.middleware.csrf.CsrfViewMiddleware',  # csrf验证
    'django.contrib.auth.middleware.AuthenticationMiddleware',  # 用户登录注册
    'django.contrib.messages.middleware.MessageMiddleware',     # 消息框架
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# 根路由
ROOT_URLCONF = 'drf04.urls'

# 模板的设置
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# 后期项目上线,使用uwsgi运行,指定的运行app
WSGI_APPLICATION = 'drf04.wsgi.application'


# 数据库的设置,可以配置多个数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# 认证的校验
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# 国际化:en-us;英文,zh-hans:中文
LANGUAGE_CODE = 'zh-hans'  # 设置成中文
TIME_ZONE = 'Asia/Shanghai'  # 因为上海在东八区,django支持上海时间
USE_I18N = True
USE_L10N = True
USE_TZ = False  # 是否用UTC时间

# 静态文件
STATIC_URL = '/static/'
drf