rest_framework_django学习笔记一(序列化器)

rest_framework_django学习笔记一(序列化器)

一、引入Django Rest Framework

1、安装

sh 复制代码
pip install djangorestframework

2、引入

python 复制代码
INSTALLED_APPS = [
	...
    'rest_framework',
]

3、原始RESTful接口写法

models.py

python 复制代码
from django.db import models

''' 测试数据 仅供参考
INSERT INTO `demo_app_author` VALUES (1, '令狐冲', 25, 1);
INSERT INTO `demo_app_author` VALUES (2, '任我行', 58, 2);
INSERT INTO `demo_app_author` VALUES (3, '任盈盈', 23, 3);
INSERT INTO `demo_app_author` VALUES (4, '扫地僧', 99, 4);
INSERT INTO `demo_app_author` VALUES (5, '乔峰', 99, 5);
INSERT INTO `demo_app_authordetail` VALUES (1, 1, '13432335433', '华山', '1994-05-23');
INSERT INTO `demo_app_authordetail` VALUES (2, 1, '13943454554', '黑木崖', '1961-08-13');
INSERT INTO `demo_app_authordetail` VALUES (3, 0, '13878934322', '黑木崖', '1996-05-20');
INSERT INTO `demo_app_authordetail` VALUES (4, 0, '13878938322', '少林', '1996-05-20');
INSERT INTO `demo_app_authordetail` VALUES (5, 0, '13878939322', '大宋', '1996-05-20');
INSERT INTO `demo_app_book` VALUES (1, '笑傲江湖', 33.30, '2023-11-11', 1);
INSERT INTO `demo_app_book` VALUES (2, '天龙八部', 33.30, '2023-11-11', 1);
INSERT INTO `demo_app_book_authors` VALUES (1, 1, 1);
INSERT INTO `demo_app_book_authors` VALUES (2, 1, 2);
INSERT INTO `demo_app_book_authors` VALUES (3, 2, 1);
INSERT INTO `demo_app_book_authors` VALUES (4, 2, 2);
INSERT INTO `demo_app_publish` VALUES (1, '华山出版社', '华山', '[email protected]');
INSERT INTO `demo_app_publish` VALUES (2, '明教出版社', '黑木崖', '[email protected]');
INSERT INTO `demo_app_publish` VALUES (2, '萧峰版社', '大宋', '[email protected]');
'''

class Book(models.Model):
	title = models.CharField(max_length=32)
	price = models.DecimalField(max_digits=5, decimal_places=2)
	pub_date = models.DateField()
	publish = models.ForeignKey("Publish", on_delete=models.CASCADE)
	authors = models.ManyToManyField("Author")
	class Meta:
		verbose_name = '书籍表'

class Publish(models.Model):
	name = models.CharField(max_length=32)
	city = models.CharField(max_length=64)
	email = models.EmailField()
	class Meta:
		verbose_name = '出版社表'

class Author(models.Model):
	name = models.CharField(max_length=32)
	age = models.SmallIntegerField()
	au_detail = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE)
	class Meta:
		verbose_name = '作者表'


class AuthorDetail(models.Model):
	gender_choices = (
	(0, "女"),
	(1, "男"),
	(2, "保密"),
	)
	gender = models.SmallIntegerField(choices=gender_choices)
	tel = models.CharField(max_length=32)
	addr = models.CharField(max_length=64)
	birthday = models.DateField()
	class Meta:
		verbose_name = '作者详情表'

urls.py

python 复制代码
urlpatterns = [
	path('books/',BookListView.as_view()),# 列表视图
	path('books/<int:id>/',BookDataView.as_view()),# 详情视图
]

vuew.py

python 复制代码
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render
from django.utils.html import escape
# Create your views here.
'''
GET  /books/         提供所有数据
POST /books/         增加一条数据
GET  /books/<pk>/    提供指定id的记录
PUT  /books/<pk>/    修改指定ID的记录
DELETE /books/<pk>/  删除指定id的记录  
'''
from django.views import View
from .models import *
class BookListView(View):
	'''
	列表视图
	'''
	def get(self,request):
		'''查询所有数据'''
		# 1、查询出所有图书模型
		book_list = Book.objects.filter().order_by('id')
		# 2、遍历出里面的每个数据模型对象,把模型对象转换成json对象
		data_list = []
		for book in book_list:
			book_dict = {
				'id':book.id,
				'title':book.title,
				'price':book.price,
				'pub_date':book.pub_date,
				'publish':{
					'id':book.publish.id,
					'name':book.publish.name,
					'city':book.publish.city,
					'email':book.publish.email,
				},
			}
			# 多堆对多
			authors_list = book.authors.filter()
			authors_data_list = []
			for authors in authors_list:
				authors_dict = {
						'id': authors.id,
						'name': authors.name,
						'age': authors.age,
						'gender': authors.au_detail.gender,
						'tel': authors.au_detail.tel,
						'addr': authors.au_detail.addr,
				}
				authors_data_list.append(authors_dict)

			book_dict['authors'] = authors_data_list
			data_list.append(book_dict)
		# 3、响应
		return JsonResponse(data_list,safe=False)
	def post(self,request):
		title = escape(request.POST.get('title',''))
		price = escape(request.POST.get('price',''))
		pub_date = escape(request.POST.get('pub_date',''))
		publish_id = escape(request.POST.get('publish_id',''))
		publish = Publish.objects.filter(pk=int(publish_id)).first()

		book = Book(
			title = title,
			price = price,
			pub_date = pub_date,
			publish = publish
		)
		book.save()
		# 新增关联
		authors = Author.objects.filter(pk__in=[1, 2])
		book.authors.add(*authors)
		book_dict = {
			'id': book.id,
			'title': book.title,
			'price': book.price,
			'pub_date': book.pub_date,
			'publish': {
				'id': book.publish.id,
				'name': book.publish.name,
				'city': book.publish.city,
				'email': book.publish.email,
			},
		}
		authors_list = book.authors.filter()
		authors_data_list = []
		for authors in authors_list:
			authors_dict = {
				'id': authors.id,
				'name': authors.name,
				'age': authors.age,
				'gender': authors.au_detail.gender,
				'tel': authors.au_detail.tel,
				'addr': authors.au_detail.addr,
			}
			authors_data_list.append(authors_dict)

		book_dict['authors'] = authors_data_list
		return JsonResponse(book_dict)


class BookDataView(View):
	''' 详情视图 '''
	def get(self,request,id):
		''' 指定某个 图书接口'''
		# 1、获取出指定id的那个模型对象
		book = Book.objects.filter(pk=id).first()
		# 2、模型对象字典
		if not book:
			return JsonResponse({'msg':"未查询到数据"})
		book_dict = {
			'id': book.id,
			'title': book.title,
			'price': book.price,
			'pub_date': book.pub_date,
			'publish': {
				'id': book.publish.id,
				'name': book.publish.name,
				'city': book.publish.city,
				'email': book.publish.email,
			},
		}
		authors_list = book.authors.filter()
		authors_data_list = []
		for authors in authors_list:
			authors_dict = {
				'id': authors.id,
				'name': authors.name,
				'age': authors.age,
				'gender': authors.au_detail.gender,
				'tel': authors.au_detail.tel,
				'addr': authors.au_detail.addr,
			}
			authors_data_list.append(authors_dict)

		book_dict['authors'] = authors_data_list
		# 3、响应
		return  JsonResponse(book_dict)
	def put(self,request,id):
		''' 修改 '''
		# 1、先获取前端传入的新数据
		# 2、将后端传入的数据就行赋值
		book_obj = Book.objects.filter(pk=id).first()
		if not book_obj:
			return JsonResponse({'msg':"未查询到信息"})
		title = escape(request.POST.get('title', ''))
		price = escape(request.POST.get('price', ''))
		pub_date = escape(request.POST.get('pub_date', ''))
		publish_id = escape(request.POST.get('publish_id', ''))

		if title:
			book_obj.title = title
		if price:
			book_obj.price = price
		if pub_date:
			book_obj.pub_date = pub_date
		if publish_id:
			publish = Publish.objects.filter(pk=int(publish_id)).first()
			book_obj.publish = publish
		book_obj.save()
		# 3、返回
		book_dict = {
			'id': book_obj.id,
			'title': book_obj.title,
			'price': book_obj.price,
			'pub_date': book_obj.pub_date,
			'publish': {
				'id': book_obj.publish.id,
				'name': book_obj.publish.name,
				'city': book_obj.publish.city,
				'email': book_obj.publish.email,
			},
		}
		authors_list = book_obj.authors.filter()
		authors_data_list = []
		for authors in authors_list:
			authors_dict = {
				'id': authors.id,
				'name': authors.name,
				'age': authors.age,
				'gender': authors.au_detail.gender,
				'tel': authors.au_detail.tel,
				'addr': authors.au_detail.addr,
			}
			authors_data_list.append(authors_dict)

		book_dict['authors'] = authors_data_list
		return JsonResponse(book_dict)


	def delete(self,request,id):
		''' 删除 '''
		delete = Book.objects.filter(pk=id).delete()
		return JsonResponse({'msg':"删除成功"})


4、快速上手

urls.py

python 复制代码
from rest_framework.routers import DefaultRouter
from django.urls import path
from .views import *
import rest_fromwork_views

urlpatterns = []

router = DefaultRouter()# 创建路由器
router.register(r'book',rest_fromwork_views.BookView)# 注册路由
urlpatterns += router.urls# 把生成好的路由拼接到urlpatterns中去

views.py

python 复制代码
'''
GET  /book/         提供所有数据
POST /book/         增加一条数据
GET  /book/<pk>/    提供指定id的记录
PUT  /book/<pk>/    修改指定ID的记录
DELETE /book/<pk>/  删除指定id的记录  
'''
from rest_framework.viewsets import ModelViewSet
from .models import *
from .serializers import *

class BookViews(ModelViewSet):
	''' 定义类视图 '''
	# 1、指定查询集  queryset 
	queryset = Book.objects.filter()
	# 2、指定序列化器  serializer_class
	serializer_class = BookSerializer

serializers.py

python 复制代码
from rest_framework import serializers
from .models import Book, Publish, Author

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'

class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'

class BookSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()
    authors = AuthorSerializer(many=True)
    class Meta:
        model = Book
        fields = '__all__'

浏览器发起请求

二、序列化器

1、序列化器的作用

1.1 对数据进行转换

序列化(输出、read_only)和反序列化(输入、write_only)

1.2进行数据的校验

判断用户发送的数据是否合法(is_valid(raise_exception=True))

2、序列化器

python 复制代码
from rest_framework import serializers
from .models import Book, Publish, Author

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()
    authors = AuthorSerializer(many=True)
    class Meta:
        model = Book
        fields = '__all__'
class NewBookSerializer(serializers.Serializer):
        id = serializers.IntegerField(label="ID",read_only=True)# read_only=True只能做输出不能做输入;write_only=True:输入
        title = serializers.CharField(label="标题",max_length=32,required=True)# required=True 必传,不写默认 True;只有当模型中 有默认值和允许为空才可以为 False
        price = serializers.DecimalField(label="价格",max_digits=5,decimal_places=2)
        pub_date = serializers.DateField()
        publish = PublishSerializer()
        authors = AuthorSerializer(many=True)

3、字段与选项

选项参数

参数名称 作用
max_length 最大长度
min_length 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最小值
min_value 最大值

通用类型

参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器
error_messages 包含错误编号与错误的信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
required 表明该字段的反序列化时必须虚入,默认值为True

4、Serializer

反序列化内容 中没有具体的 保存和修改方法,需要自己重写保存和修改方法。

python 复制代码
from rest_framework import serializers
class NewPublishSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID",read_only=True)
    name = serializers.CharField(label="出版社名称",max_length=32,required=True)
    city = serializers.CharField(label="城市",max_length=64,required=True)
    email = serializers.EmailField(label="邮箱",required=True)
    def create(self, validated_data):
        '''
        使用方法
        NewPublishSerializer(data=data)
        当调用序列化器的 save() 方法时,如果当初创建序列化器对象是没有 instance 传参数
        :param validated_data: 得到的是 反序列化后的字段数据
        :return:
        '''
        # 创建内容
        publish = Publish.objects.create(**validated_data)
        return publish

    def update(self, instance, validated_data):
        '''
        使用方法:
         NewPublishSerializer(instance=publish,data=data)
        重写 update 方法  NewPublishSerializer(instance=publish,data=data)
        如果创建序列化器时给 instance 传了参数,在调用序列化器的 save() 方法时实现时机会调用当前的 update
        :param instance: 要修改的模型对象
        :param validated_data:得到的是 反序列化后的字段数据
        :return: 返回修改后的模型对象
        '''
        instance.name = validated_data.get('name')
        instance.city = validated_data.get('city')
        instance.email = validated_data.get('email')
        instance.save()
        return instance

新增

python 复制代码
from django.test import TestCase
from demo_app.serializers import *
data = {
	'name':'武当山出版社',
	'city':'武当山',
	'email':'[email protected]',
}
serializer = NewPublishSerializer(data=data)
is_valid = serializer.is_valid()# 调用序列化的校验方法  True 或 False
print('校验是否通过is_valid:',is_valid)
errors = serializer.errors # 获取校验的错误信息
print('校验不通过内容原因errors:',errors)
#serializer.validated_data # 获取反序列化校验后的数据还是字段
print(serializer.validated_data)
publish = serializer.save()

修改方法

python 复制代码
from demo_app.serializers import *
data = {
	'name':'武当山出版社',
	'city':'武当山1111',
	'email':'[email protected]',
}
publish_obj = Publish.objects.get(id=3)
# 调用
serializer = NewPublishSerializer(instance=publish_obj,data=data)
is_valid = serializer.is_valid(raise_exception=True)
publish = serializer.save()

说明

调用序列化器的 .save() 方法,调用save 时会判断当初始创建序列化器时是否传入 instance ,如果传了 instance 也传了data 那么调用 save 实际调用序列化器中的 update() 方法反之就是调用序列化器中的 create 方法。

5、ModelSerializer

如果我们想要使用序列化器对应的是django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

ModelSerilizer 与常规的Serializer 相同,但提供了:

  • ModelSerializer可以工具模型自动生成序列化器中的字段
  • ModelSerializer它里面已经帮我们实现了create和update方法

1、定义

创建BookSerializer

python 复制代码
from rest_framework import serializers
from .models import Book, Publish, Author,AuthorDetail
class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()# 外键
    authors = AuthorSerializer(many=True)# 多对多
    class Meta:
        model = Book
        fields = '__all__'
  • model 指明参照那个模型类
  • fields 指明为模型类的哪些字段生成

通过 ModelSerializer 实现字段自动生成

1.1 fields

只要一部分字段实现方法1 fields

python 复制代码
from rest_framework import serializers
from .models import Book, Publish, Author,AuthorDetail
class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
class AuthorDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = AuthorDetail
        fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()
    authors = AuthorSerializer(many=True)
    class Meta:
        model = Book
        # fields = '__all__' # 全部字段
        fields = ['id','title','publish','authors']# 只要list中的字段
1.2 exclude

只要一部分字段实现方法2 exclude

python 复制代码
from rest_framework import serializers
from .models import Book, Publish, Author,AuthorDetail
class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
class AuthorDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = AuthorDetail
        fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()
    authors = AuthorSerializer(many=True)
    class Meta:
        model = Book
        # fields = '__all__' # 全部字段
        # fields = ['id','title','publish','authors']# 只要list中的字段
        exclude = ['pub_date'] #除了 pub_date 字段不映射 其他字段都要
1.3 extra_kwargs

其中自动生成的 字段中有些默认值会出现 问题例如 authors 中的 age字段 最小值是 -32768 在实际中最小值不可能小于0因此可以通过 extra_kwargs 来进行自定义限制

python 复制代码
from rest_framework import serializers
from .models import Book, Publish, Author,AuthorDetail
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
        # 对 额外的字段进行修改
        extra_kwargs = {
            'age':{'min_value':0}# age 是对应字段名,min_value 对应的校验属性,都是以字典的形式
        }
1.4 read_only_fields

只对某些字段进行序列化

python 复制代码
from rest_framework import serializers
from .models import Book, Publish, Author,AuthorDetail
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
        # 对 额外的字段进行修改
        # extra_kwargs = {
        #     'age':{'min_value':0}
        # }
        read_only_fields = ['age'] # 只对某些字段进行序列化

我们可以在python manage.py shell 中查看自动生成的 BookSerializer 的具体实现

我们可以在python manage.py shell 中查看自动生成的 BookSerializer 的具体实现

三、序列化

提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其他库自动和反序列化;

提供了丰富的类视图、Mixin扩展类,简化视图的编写;

丰富的定制层级:函数视图、类视图、视图集合到自动生成API,满足各种需求;

多种身份认证和权限认证的支持;

内置限流系统;

只管的API web界面;

扩展性,插件丰富;

序列化器的作用:

复制代码
1、进行数据的校验。
2、对数据对象进行转换。

1、提示

在开发REST API 接口时,视图中的主要有三件事:

  1. 将 请求的数据(如JSON格式)转换为模型类对象(反序列化)
  2. 操作数据库
  3. 将模型类对象转换为响应的数据(如JSON格式)(序列化)

2、序列化(Serializer)

2.1 概念

将程序中的一个数据结构类型转换为其他格式(字典、JSON、XML等)

2.2 序列化行为

python 复制代码
for book in book_list:
    book_dict = {
        'id':book.id,
        'title':book.title,
        'price':book.price,
        'pub_date':book.pub_date,
        'publish':{
            'id':book.publish.id,
            'name':book.publish.name,
            'city':book.publish.city,
            'email':book.publish.email,
        },
    }
    # 多对多
    authors_list = book.authors.filter()
    authors_data_list = []
    for authors in authors_list:
        authors_dict = {
            'id': authors.id,
            'name': authors.name,
            'age': authors.age,
            'gender': authors.au_detail.gender,
            'tel': authors.au_detail.tel,
            'addr': authors.au_detail.addr,
        }
        authors_data_list.append(authors_dict)

book_dict['authors'] = authors_data_list
data_list.append(book_dict)
# 3、响应
return JsonResponse(data_list,safe=False)

2.3序列化时机

当前端需给前端响应模型数据时,需要将模型数据序列化成前端需要的格式。

2.4 使用方式

在序列化器中有两个属性 instancedata

instance参数: 模型、查询集、字典

python 复制代码
#如果只给  instance 形参传递参数表示做序列化
serializer = BookSerializer(instance=book)
serializer.data # 就可以获取序列化后的数据

测试一

tests.py

python 复制代码
from django.test import TestCase
# Create your tests here.
from demo_app.serializers import *
from demo_app.models import *
datas = Book.objects.filter()
print("查询出的数据内容有多少条:",datas.count())
serializer = NewBookSerializer(instance=datas,many=True)# many=True:表示有多条数据,当只有一条数据的时候就不用many=False;默认many=False
print(serializer.data)
# 执行上述代码使用
'''
python manage.py test
'''

测试二

在序列化器中多增加一列

python 复制代码
'''serializers.py'''
from rest_framework import serializers
class NewBookSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id",read_only=True)
    title = serializers.CharField(label="标题",max_length=32)
    price = serializers.DecimalField(label="价格",max_digits=5,decimal_places=2)
    pub_date = serializers.DateField()
    publish = PublishSerializer()
    authors = AuthorSerializer(many=True)
    helle = serializers.CharField()# 多余字段
python 复制代码
'''tests.py'''
from django.test import TestCase
# Create your tests here.
from demo_app.serializers import *
from demo_app.models import *
data = Book.objects.get(id=1)
data.helle = "测试多增加字段内容"
# print("查询出的数据内容有多少条:",data.count())
serializer = NewBookSerializer(instance=data)# many=True:表示有多条数据,当只有一条数据的时候就不用many
print(serializer.data)
'''
python manage.py test
'''

2.5 外键序列化器

2.5.1 PrimaryKeyRelatedField(正向)

主要字段 serializers.PrimaryKeyRelatedField

python 复制代码
class NewBookSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id",read_only=True)
    title = serializers.CharField(label="标题",max_length=32)
    price = serializers.DecimalField(label="价格",max_digits=5,decimal_places=2)
    pub_date = serializers.DateField()
    # read_only = True :只做序列化
    # queryset=Publish.objects.all() 当输入查询时不是Publish这里面的数据就会 报错
    # PrimaryKeyRelatedField 外键关联
    publish = serializers.PrimaryKeyRelatedField(label="出版社",read_only=True,queryset=Publish.objects.all())
python 复制代码
from demo_app.serializers import *
from demo_app.models import *
data = Book.objects.get(id=1)
data.helle = "测试多增加字段内容"
# print("查询出的数据内容有多少条:",data.count())
serializer = NewBookSerializer(instance=data)# many=True:表示有多条数据,当只有一条数据的时候就不用many
print(serializer.data)

**注意:**默认是将 关联的id查询出来。

2.5.2 StringRelatedField(正向)
python 复制代码
class NewBookSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id",read_only=True)
    title = serializers.CharField(label="标题",max_length=32)
    price = serializers.DecimalField(label="价格",max_digits=5,decimal_places=2)
    pub_date = serializers.DateField()
    # read_only = True :只做序列化
    # queryset=Publish.objects.all() 当输入查询时不是Publish这里面的数据就会 报错
    # PrimaryKeyRelatedField 外键关联
    publish = serializers.StringRelatedField(label="出版社",read_only=True)
    # publish = PublishSerializer()
    # authors = AuthorSerializer(many=True)
    # helle = serializers.CharField()# 多余字段
python 复制代码
from django.test import TestCase
# Create your tests here.
from demo_app.serializers import *
from demo_app.models import *
data = Book.objects.get(id=1)
data.helle = "测试多增加字段内容"
# print("查询出的数据内容有多少条:",data.count())
serializer = NewBookSerializer(instance=data)# many=True:表示有多条数据,当只有一条数据的时候就不用many
print(serializer.data)

**注意:**返回值是 对象 obje (*) 的字符串

2.5.3 外键序列化器(正向)

将关联模型对象的序列化器中所有字段序列化出来

python 复制代码
from rest_framework import serializers
from .models import Book, Publish, Author

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'
class NewBookSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id",read_only=True)
    title = serializers.CharField(label="标题",max_length=32)
    price = serializers.DecimalField(label="价格",max_digits=5,decimal_places=2)
    pub_date = serializers.DateField()
    # read_only = True :只做序列化
    # queryset=Publish.objects.all() 当输入查询时不是Publish这里面的数据就会 报错
    # PrimaryKeyRelatedField 外键关联
    # publish = serializers.StringRelatedField(label="出版社",read_only=True)
    publish = PublishSerializer()
    # authors = AuthorSerializer(many=True)
    # helle = serializers.CharField()# 多余字段
2.5.4 外键反向序列化

出版社反向获取 书籍;

python 复制代码
# coding=utf-8
'''
@date:2023/11/15 11:48
@mail:[email protected]
@Content: 序列化器
'''
from rest_framework import serializers
from .models import Book, Publish, Author

class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
class NewBookSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id",read_only=True)
    title = serializers.CharField(label="标题",max_length=32)
    price = serializers.DecimalField(label="价格",max_digits=5,decimal_places=2)
    pub_date = serializers.DateField()
    # publish = PublishSerializer()
    # authors = AuthorSerializer(many=True)
    # helle = serializers.CharField()# 多余字段

class NewPublishSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID",read_only=True)
    name = serializers.CharField(label="出版社名称",max_length=32,required=True)
    city = serializers.CharField(label="城市",max_length=64,required=True)
    email = serializers.EmailField(label="邮箱",required=True)
    book_set = NewBookSerializer(many=True)  # 注意
python 复制代码
from django.test import TestCase
# Create your tests here.
from demo_app.serializers import *
from demo_app.models import *
data = Publish.objects.get(id=1)
data.helle = "测试多增加字段内容"
# print("查询出的数据内容有多少条:",data.count())
serializer = NewPublishSerializer(instance=data)# many=True:表示有多条数据,当只有一条数据的时候就不用many
print(serializer.data)

**注意:**使用 modesel名小写 + _set

2.6 多对多序列化

2.6.1 使用对应的序列化器(正向)
python 复制代码
# coding=utf-8
'''
@date:2023/11/15 11:48
@mail:[email protected]
@Content: 序列化
'''
from rest_framework import serializers
from .models import Book, Publish, Author
class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
class NewBookSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id",read_only=True)
    title = serializers.CharField(label="标题",max_length=32)
    price = serializers.DecimalField(label="价格",max_digits=5,decimal_places=2)
    pub_date = serializers.DateField()
    publish = PublishSerializer()
    authors = AuthorSerializer(many=True)# 注意多对多 时 many=True
    # helle = serializers.CharField()# 多余字段
python 复制代码
from django.test import TestCase
# Create your tests here.
from demo_app.serializers import *
from demo_app.models import *
data = Book.objects.get(id=1)
data.helle = "测试多增加字段内容"
# print("查询出的数据内容有多少条:",data.count())
serializer = NewBookSerializer(instance=data)# many=True:表示有多条数据,当只有一条数据的时候就不用many
print(serializer.data)
2.6.2 多对多 (反向)
python 复制代码
# coding=utf-8
'''
@date:2023/11/15 11:48
@mail:[email protected]
@Content: 序列化器
'''
from rest_framework import serializers
from .models import Book, Publish, Author,AuthorDetail

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'

class AuthorDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = AuthorDetail
        fields = '__all__'

class NewBookSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id",read_only=True)
    title = serializers.CharField(label="标题",max_length=32)
    price = serializers.DecimalField(label="价格",max_digits=5,decimal_places=2)
    pub_date = serializers.DateField()
    # publish = PublishSerializer()
    # authors = AuthorSerializer(many=True)
    # helle = serializers.CharField()# 多余字段

class NewAuthSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id", read_only=True)
    name = serializers.CharField(label="姓名",max_length=32)
    age = serializers.CharField(label="年龄",max_length=32)
    au_detail = AuthorDetailSerializer()
    book_set = NewBookSerializer(many=True)
python 复制代码
from django.test import TestCase
# Create your tests here.
from demo_app.serializers import *
from demo_app.models import *
data = Author.objects.get(id=1)
data.helle = "测试多增加字段内容"
# print("查询出的数据内容有多少条:",data.count())
serializer = NewAuthSerializer(instance=data)# many=True:表示有多条数据,当只有一条数据的时候就不用many
print(serializer.data)

注意: 反向序列化使用 模型名+_set 即可

总结

  1. 注意 many 的使用,many默认为 False;当需要序列化多个是记得 Many=True;
  2. 注意需求,序列化的反向正向;
  3. 将模型转换为JSON数据步骤:
    1. 定义序列化器类(模型名 / 类视图名+Serializer) 继承 Sarializer;
    2. 定义序列化器中的字段参照模型(序列化器中的字段可以比模型多或少 如果表示是模型中的字段在序列化器中这个字段名应该和模型中字段名一致)
  4. 如果在多里面关联序列化一(外键)如果在一里面关联序列化多(多的一方模型小写_set)
  5. 如果在一的一方关联序列化多时,需要指定关联字段many=True
  6. 将要序列化模型或查询集 传给序列化器类的 instance 参数 如果传的是查询集 多指定 many=True
  7. 获取序列化后的数据 序列化器对象 .data 属性

3、反序列化(Serializer)

拿到前端传入的数据 ---》 序列化器的data --》 调用序列化器的 .is_valid() 方法进行校验 ---》 调用序列化器的 .save() 方法。

3.1 概念

将其他格式(字典、JSON、XML等)转换为程序中的数据,例如JSON字符串转换为django中的模型类对象。

3.2反序列化行为

python 复制代码
title = escape(request.POST.get('title',''))
price = escape(request.POST.get('price',''))
pub_date = escape(request.POST.get('pub_date',''))
publish_id = escape(request.POST.get('publish_id',''))
publish = Publish.objects.filter(pk=int(publish_id)).first()
book = Book(
    title = title,
    price = price,
    pub_date = pub_date,
    publish = publish
)

3.3 反序列化时机

当需要将用户发送的数据存储到数据库之前,需要使用反序列化。

3.4 使用方式

在序列化器中有两个属性 instancedata

复制代码
#如果只给  instance 形参传递参数表示做序列化
serializer = BookSerializer(data=jsondata)
serializer.data # 就可以获取反序列化数据

反序列化 = 前端发送的数据 ---》 经过验证 --》python字典 ---》 save --》 模型对象

**案例使用 Serializer **

反序列化内容 中没有具体的 保存和修改方法,需要自己重写保存和修改方法。

python 复制代码
from rest_framework import serializers
class NewPublishSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID",read_only=True)
    name = serializers.CharField(label="出版社名称",max_length=32,required=True)
    city = serializers.CharField(label="城市",max_length=64,required=True)
    email = serializers.EmailField(label="邮箱",required=True)
    def create(self, validated_data):
        '''
        使用方法
        NewPublishSerializer(data=data)
        当调用序列化器的 save() 方法时,如果当初创建序列化器对象是没有 instance 传参数
        :param validated_data: 得到的是 反序列化后的字段数据
        :return:
        '''
        # 创建内容
        publish = Publish.objects.create(**validated_data)
        return publish

    def update(self, instance, validated_data):
        '''
        使用方法:
         NewPublishSerializer(instance=publish,data=data)
        重写 update 方法  NewPublishSerializer(instance=publish,data=data)
        如果创建序列化器时给 instance 传了参数,在调用序列化器的 save() 方法时实现时机会调用当前的 update
        :param instance: 要修改的模型对象
        :param validated_data:得到的是 反序列化后的字段数据
        :return: 返回修改后的模型对象
        '''
        instance.name = validated_data.get('name')
        instance.city = validated_data.get('city')
        instance.email = validated_data.get('email')
        instance.save()
        return instance

新增

python 复制代码
from django.test import TestCase
from demo_app.serializers import *
data = {
	'name':'武当山出版社',
	'city':'武当山',
	'email':'[email protected]',
}
serializer = NewPublishSerializer(data=data)
is_valid = serializer.is_valid()# 调用序列化的校验方法  True 或 False
print('校验是否通过is_valid:',is_valid)
errors = serializer.errors # 获取校验的错误信息
print('校验不通过内容原因errors:',errors)
#serializer.validated_data # 获取反序列化校验后的数据还是字段
print(serializer.validated_data)
publish = serializer.save()

修改方法

python 复制代码
from demo_app.serializers import *
data = {
	'name':'武当山出版社',
	'city':'武当山1111',
	'email':'[email protected]',
}
publish_obj = Publish.objects.get(id=3)
# 调用
serializer = NewPublishSerializer(instance=publish_obj,data=data)
is_valid = serializer.is_valid(raise_exception=True)
publish = serializer.save()

调用序列化器的 .save() 方法,调用save 时会判断当初始创建序列化器时是否传入 instance ,如果传了 instance 也传了data 那么调用 save 实际调用序列化器中的 update() 方法反之就是调用序列化器中的 create 方法。

3.4、要属性和方法

1 is_valid()

在获取反序列化的数据前,必须调用 is_valid() 方法进行验证,验证成功返回True,否则返回False

2error 属性

验证失败,可以通过序列化器对象的error属性获取错误学习,返回字典,包含了字段和字 段的错误。

3validated_data属性

验证成功,可以通过序列化器对象的 validated_data 属性获取数据。

4context 参数是额外的添加数据
python 复制代码
# 可以通过序列化器 进行context 进行传输数据
publish = NewPublishSerializer(instance=None,data=data,context={'request':request})

# 获取context 中的数据
class NewPublishSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID",read_only=True)
    name = serializers.CharField(label="出版社名称",max_length=32,
                                 required=True,validators=[custom_fun1,custom_fun2]
                                 )
    city = serializers.CharField(label="城市",max_length=64,required=True)
    email = serializers.EmailField(label="邮箱",required=True)
    def create(self, validated_data):
        '''
        当调用序列化器的 save() 方法时,如果当初创建序列化器对象是没有 instance 传参数
        :param validated_data: 得到的是 反序列化后的字段数据
        :return:
        '''
        # 创建内容
        publish = Publish.objects.create(**validated_data)
        return publish

    def update(self, instance, validated_data):
        '''
        重写 update 方法
        如果创建序列化器时给 instance 传了参数,在调用序列化器的 save() 方法时实现时机会调用当前的 update
        :param instance: 要修改的模型对象
        :param validated_data:得到的是 反序列化后的字段数据
        :return: 返回修改后的模型对象
        '''
        request = self.context['request']
        instance.name = validated_data.get('name')
        instance.city = validated_data.get('city')
        instance.email = validated_data.get('email')
        instance.save()
        return instance

3.5、反序列化自定义校验字段

1 单个字段校验(validate_+字段名称)
python 复制代码
class NewPublishSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID",read_only=True)
    name = serializers.CharField(label="出版社名称",max_length=32,required=True)
    city = serializers.CharField(label="城市",max_length=64,required=True)
    email = serializers.EmailField(label="邮箱",required=True)

    # 序列化器中单独增加校验逻辑
    def validate_name(self,value):
        '''
        复杂校验内容数据   validate_+字段名称
        :param value:  当前字段值
        :return: 返回value
        '''
        if '出版社' not in value:
            # 只要在序列化器中  抛出的异常都叫做  ValidationError 异常
            raise serializers.ValidationError('名称中不包含 出版社等字')
        return value # 将校验内容返回回去

测试代码

python 复制代码
from demo_app.serializers import *
data = {
	'name':'武当',
	# 'city':'武当山',
	'email':'[email protected]',
}
serializer = NewPublishSerializer(data=data)
is_valid = serializer.is_valid()# 调用序列化的校验方法  True 或 False
print('校验是否通过is_valid:',is_valid)
#is_valid2 = serializer.is_valid(raise_exception=True)# raise_exception=True 如果有异常会自动输出异常# 就不用在.error 获取异常
#print('校验是否通过is_valid2:',is_valid2)
errors = serializer.errors # 获取校验的错误信息
print('校验不通过内容原因errors:',errors)
serializer.validated_data # 获取反序列化校验后的数据还是字段
2多个字段联合校验( validate)
python 复制代码
class NewPublishSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID",read_only=True)
    name = serializers.CharField(label="出版社名称",max_length=32,required=True)
    city = serializers.CharField(label="城市",max_length=64,required=True)
    email = serializers.EmailField(label="邮箱",required=True)
    def validate(self,attrs):
        '''
        同时校验多个字段  联合校验
        :param attrs: 里面是前端 传入过来的所有数据
        :return: 返回数据
        # 在联合校验中,可以对单个字段进行校验也可以对多个字段进行校验
        # 也可以对在传入的字段中增加 一个属性
        '''
        name = attrs['name']
        print(attrs)
        if '出版社' not in name:
            # 只要在序列化器中  抛出的异常都叫做  ValidationError 异常
            raise serializers.ValidationError('名称中不包含 出版社等字')
        return attrs
python 复制代码
from demo_app.serializers import *
data = {
	'name':'武当',
	'city':'武当山',
	'email':'[email protected]',
}
serializer = NewPublishSerializer(data=data)
is_valid = serializer.is_valid()# 调用序列化的校验方法  True 或 False
print('校验是否通过is_valid:',is_valid)
errors = serializer.errors # 获取校验的错误信息
print('校验不通过内容原因errors:',errors)
# serializer.validated_data # 获取反序列化校验后的数据还是字段

注意:

  • 校验字段 统一写法为 validate_+字段名称;
  • 校验不通过统一抛出异常:serializers.ValidationError();
  • 校验顺序:序列化器中定义的校验先开始,才走 单个字段校验,最后才是联合校验;
3 自定义方法校验(validators参数)

在字段中添加 validators 选项参数,可以补充验证行为;

**使用:**当多个字段存在相同的校验就可以使用自定义的方法校验。

python 复制代码
def custom_fun1(value):
    if '出版社' not in value:
        # 只要在序列化器中  抛出的异常都叫做  ValidationError 异常
        raise serializers.ValidationError('名称中不包含 出版社等字')
    return value
def custom_fun2(value):
    if 'python' in value:
        # 只要在序列化器中  抛出的异常都叫做  ValidationError 异常
        raise serializers.ValidationError('名称中不能包含 python')
    return value

class NewPublishSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="ID",read_only=True)
    name = serializers.CharField(label="出版社名称",max_length=32,
                                 required=True,validators=[custom_fun1,custom_fun2]
                                 )
    city = serializers.CharField(label="城市",max_length=64,required=True)
    email = serializers.EmailField(label="邮箱",required=True)
python 复制代码
from django.test import TestCase
from demo_app.serializers import *
data = {
	'name':'武当python',
	'city':'武当山',
	'email':'[email protected]',
}
serializer = NewPublishSerializer(data=data)
is_valid = serializer.is_valid()# 调用序列化的校验方法  True 或 False
print('校验是否通过is_valid:',is_valid)
errors = serializer.errors # 获取校验的错误信息
print('校验不通过内容原因errors:',errors)
# serializer.validated_data # 获取反序列化校验后的数据还是字段

4、总结

在开发REST API接口时,我们在视图中需要做的最核心的事是:

  • 将数据库数据序列化为前端所需要的格式并返回;
  • 将前端发送的数据反序列化为模型类对象,并保存到数据库中;
  • 反序列化步骤:
    • 获取前端楚然的缴纳字典数据;
    • 创建序列化器给序列化器的 data参数传参(要以关键字方式传递);
    • 调用序列化器的 .is_valid(raise_excption=True)进行校验,如果校验出错会自动抛出错误信息;
    • 如果校验成功,就调用save() 方法。(当调用序列化器的save方法时,会执行序列化器中的 create方法或update方法。如果要使用update方法那么就需要将 BookSerializer(instance=book,data=data),只有传了模型此时修改,否则就是新增。)查看序列化器的;
  • 使用Serializer 构造序列化器时,调用序列化器的 .save() 方法,调用save 时会判断当初始创建序列化器时是否传入 instance ,如果传了 instance 也传了data 那么调用 save 实际调用序列化器中的 update() 方法反之就是调用序列化器中的 create 方法。(代码实现:四 --》 4 Serializer);
  • 反序列化会自动完成序列化;
  • 序列化就是将模型转为字典;

其他笔记

序列化器

视图路由

相关推荐
阿阳微客23 分钟前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏
Chef_Chen5 小时前
从0开始学习R语言--Day18--分类变量关联性检验
学习
键盘敲没电5 小时前
【IOS】GCD学习
学习·ios·objective-c·xcode
海的诗篇_6 小时前
前端开发面试题总结-JavaScript篇(一)
开发语言·前端·javascript·学习·面试
AgilityBaby6 小时前
UE5 2D角色PaperZD插件动画状态机学习笔记
笔记·学习·ue5
AgilityBaby6 小时前
UE5 创建2D角色帧动画学习笔记
笔记·学习·ue5
武昌库里写JAVA8 小时前
iview Switch Tabs TabPane 使用提示Maximum call stack size exceeded堆栈溢出
java·开发语言·spring boot·学习·课程设计
一弓虽9 小时前
git 学习
git·学习
Moonnnn.11 小时前
【单片机期末】串行口循环缓冲区发送
笔记·单片机·嵌入式硬件·学习
viperrrrrrrrrr711 小时前
大数据学习(131)-Hive数据分析函数总结
大数据·hive·学习