ListModelSerializer模块
ListModelSerializer模块
一 、自定义反序列化字段
# 一些只参与反序列化的字段,但是不是与数据库关联的
# 在序列化类中规定,并在校验字段时从校验的参数字典中剔除
class PublishModelSerializer(serializers.ModelSerializer):
# 自定义不入库的 反序列化 字段
re_name = serializers.CharField(write_only=True)
class Meta:
model = models.Publish
fields = ('name', 're_name', 'address')
def validate(self, attrs):
name = attrs.get('name')
re_name = attrs.pop('re_name') # 剔除
if name != re_name:
raise serializers.ValidationError({'re_name': '确认名字有误'})
return attrs
二 、模型类中自定义序列化深度
# model类中自定义插拔的外键序列化字段,可以采用外键关联表的序列化类来完成深度查询
class Book(BaseModel):
# ...
@property
def publish_detail(self):
from . import serializers
data = serializers.PublishModelSerializer(self.publish).data
return data
三 、接口操作总结
# 单查群查、单删群删、单增群增、单改群改
3.1 路由层:api/url.py
from django.conf.urls import url
from . import views
urlpatterns = [
# ...
url(r'^v3/books/$', views.BookV3APIView.as_view()),
url(r'^v3/books/(?P<pk>.*)/$', views.BookV3APIView.as_view()),
]
3.2模型层:api/models.py
# 修改部分:取消book类 name 与 publish 联合唯一,
from django.db import models
from utils.model import BaseModel
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.png')
publish = models.ForeignKey(to='Publish', null=True,
related_name='books',
db_constraint=False,
on_delete=models.DO_NOTHING,
)
authors = models.ManyToManyField(to='Author', null=True,
related_name='books',
db_constraint=False,
)
@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
@property
def publish_bac(self):
from . import serializers
data = serializers.PublishModelSerializer(self.publish).data
return data
class Meta:
db_table = 'old_boy_book'
verbose_name = '书籍'
verbose_name_plural = verbose_name
# 联合唯一
# unique_together = ('name', 'publish')
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 = 'old_boy_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()
@property
def mobile(self):
return self.detail.mobile
class Meta:
db_table = 'old_boy_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', null=True,
related_name='detail',
db_constraint=False,
on_delete=models.CASCADE
)
class Meta:
db_table = 'old_boy_author_detail'
verbose_name = '作者详情'
verbose_name_plural = verbose_name
def __str__(self):
return '%s的详情' % self.author.name
3.3 序列化层
api/serializers.py
# 群增与群改反序列化实现
# 1)ModelSerializer默认不通过群改功能,需要在Meta中设置 list_serializer_class
# 2)自定义ListSerializer子类,重写update方法,将子类绑定给 list_serializer_class
# 3)重写update方法中通过 代表要更新的对象们instance 及 提供的更新数据们validated_data
# 得到 更新后的对象们instance 返回
class BookV3ListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
'''
:param instance: [book_obj1, ..., book_obj2]
:param validated_data: [{更新数据的字段}, ..., {更新数据的字段}]
:return: [book_new_obj1, ..., book_new_obj2]
'''
for index, obj in enumerate(instance): # type: int, models.Book
# 单个对象数据更新 - 一个个属性更新值
for attr, value in validated_data[index].items():
# 对象有更新数据字典的key对应的属性,才完成该属性的值更新
if hasattr(obj, attr):
setattr(obj, attr, value)
# 信息同步到数据库
obj.save()
return instance
class BookV3ModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ('name', 'price', 'publish', 'authors', 'img', 'publish_name', 'authors_info')
list_serializer_class = BookV3ListSerializer
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')
if models.Book.objects.filter(name=name, publish=publish):
raise serializers.ValidationError({'book': '书籍以存在'})
return attrs
3.4 视图层
api/views.py
class BookV3APIView(APIView):
# 单查群查
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first()
if not book_obj:
return APIResponse(1, 'pk error')
book_ser = serializers.BookV3ModelSerializer(book_obj)
return APIResponse(0, 'ok', results=book_ser.data)
book_query = models.Book.objects.filter(is_delete=False).all().order_by('-id')
book_ser = serializers.BookV3ModelSerializer(book_query, many=True)
return APIResponse(0, 'ok', results=book_ser.data)
# 单增群增
def post(self, request, *args, **kwargs):
# 单增 /books/ data {}
# 群增 /books/ data [{}, ..., {}]
request_data = request.data
if isinstance(request_data, dict):
data = [request_data, ]
elif isinstance(request_data, list):
data = request_data
else:
return APIResponse(1, '数据格式有误')
book_ser = serializers.BookV3ModelSerializer(data=data, many=True)
if book_ser.is_valid():
book_obj_list = book_ser.save()
return APIResponse(0, 'ok',
results=serializers.BookV3ModelSerializer(book_obj_list, many=True).data
)
else:
return APIResponse(1, '添加失败', results=book_ser.errors)
"""
1)先确定要更新的对象 主键们 与 数据们
2)通过校验数据库剔除 已删除的对象 与 不存在的对象
主键们 => 剔除过程 => 可以修改的对象们
数据们 => 剔除过程 => 可以修改的对象们对应的数据们
3)反序列化及校验过程
通过 => save() 完成更新
失败 => ser_obj.errors 返回
"""
# 单改群改
def patch(self, request, *args, **kwargs):
# 单改 /books/(pk)/ data {"name": "new_name", ...}
# 群改 /books/ data [{"pk": 1, "name": "new_name", ...}, ...,{"pk": n, "name": "new_name", ...}]
# 结果:
# pks = [1, ..., n] => book_query => instance
# data = [{"name": "new_name", ...}, ..., {"name": "new_name", ...}] => data
# 数据预处理
pk = kwargs.get('pk')
request_data = request.data
if pk:
if not isinstance(request_data, dict):
return APIResponse(1, '单改数据有误')
pks = [pk, ]
data = [request_data, ]
elif isinstance(request_data, list):
try:
pks = []
for dic in request_data:
pks.append(dic.pop('pk'))
data = request_data
except:
return APIResponse(1, '群改数据有误')
else:
return APIResponse(1, '数据格式有误')
# 将 已删除的书籍 与 不存在的书籍 剔除 (提供修改的数据相对应也剔除)
book_query = []
filter_data = []
for index, pk in enumerate(pks):
book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first()
if book_obj:
book_query.append(book_obj)
filter_data.append(data[index])
# 反序列化完成数据的修改
book_ser = serializers.BookV3ModelSerializer(instance=book_query, data=filter_data, many=True, partial=True)
if book_ser.is_valid():
book_obj_list = book_ser.save()
return APIResponse(1, 'ok',
results=serializers.BookV3ModelSerializer(book_obj_list, many=True).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)
if not book_query.update(is_delete=True): # 操作的记录大于0就记录删除成功
return APIResponse(1, '删除失败')
return APIResponse(0, '删除成功')
ListModelSerializer模块的更多相关文章
- day70_10_16drf组件响应模块,异常模块和序列化模块。
一.解析模块 为什么要配置解析模块? 1)drf给我们通过了多种解析数据包方式的解析类. 2)我们可以通过配置来控制前台提交的哪些格式的数据后台在解析,哪些数据不解析. 3)全局配置就是针对每一个视图 ...
- DRF框架(二)——解析模块(parsers)、异常模块(exception_handler)、响应模块(Response)、三大序列化组件介绍、Serializer组件(序列化与反序列化使用)
解析模块 为什么要配置解析模块 1)drf给我们提供了多种解析数据包方式的解析类 form-data/urlencoded/json 2)我们可以通过配置来控制前台提交的哪些格式的数据后台在解析,哪些 ...
- drf解析模块,异常模块,响应模块,序列化模块
复习 """ 1.接口:url+请求参数+响应参数 Postman发送接口请求的工具 method: GET url: https://api.map.baidu.com ...
- drf框架的解析模块-异常处理模块-响应模块-序列化模块
解析模块 为什么要配置解析模块 (1).drf给我们通过了多种解析数据包方式的解析类. (2).我们可以通过配置来控制前台提交的那些格式的数据台解析,那些数据不解析. (3).全局配置就是针对一个视图 ...
- npm 私有模块的管理使用
你可以使用 NPM 命令行工具来管理你在 NPM 仓库的私有模块代码,这使得在项目中使用公共模块变的更加方便. 开始前的工作 你需要一个 2.7.0 以上版本的 npm ,并且需要有一个可以登陆 np ...
- node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理
一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...
- ES6模块import细节
写在前面,目前浏览器对ES6的import支持还不是很好,需要用bable转译. ES6引入外部模块分两种情况: 1.导入外部的变量或函数等: import {firstName, lastName, ...
- Python标准模块--ContextManager
1 模块简介 在数年前,Python 2.5 加入了一个非常特殊的关键字,就是with.with语句允许开发者创建上下文管理器.什么是上下文管理器?上下文管理器就是允许你可以自动地开始和结束一些事情. ...
- Python标准模块--Unicode
1 模块简介 Python 3中最大的变化之一就是删除了Unicode类型.在Python 2中,有str类型和unicode类型,例如, Python 2.7.6 (default, Oct 26 ...
随机推荐
- Java Web 项目的文件/文件夹上传下载
需求: 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验: 内网百兆网络上传速度为12MB/S 服务器内存占用低 支持文件夹上传,文件夹中的文件数量达到1万个以上,且包 ...
- JS全局变量是如何工作的?
JS全局变量是如何工作的? <script> const one = 1; var two = 2; </script> <script> // All scrip ...
- Break关键字和Continue关键字
1.Break关键字 在循环体内,只要代码遇到break,程序立马结束当前循环. 当前循环指的是break语句所在的循环体.(直接跳到大括号外) // 例1: 1到10,第一是数字是2的倍数,控制台输 ...
- CURL shell 使用
#! /bin/bash requrl="http://www.baidu.com/xxxxxx" while true do html=$(curl -s "$requ ...
- Comet OJ 2019 夏季欢乐赛题解
Comet OJ 2019 夏季欢乐赛题解 我是来骗访问量的 A 完全k叉树 \(n\)个点的完全k叉树的直径. 直接做 B 距离产生美 直接做 C 烤面包片 \(n!!!\mod p\) 显然\(n ...
- C博客作业00——我的第一篇博客
1.你对网络专业或计算机专业了解是怎样? 初看字眼,便觉得是理工性很强的专业,所以需要较强的开拓思维,创新精神,探索未知事物的勇气,才能掌握并且熟练应用相关知识.计算机类专业都需要学习计算机语言,而计 ...
- JS和JQuery实现Button绑定键盘Enter事件实现提交
JavaScript实现方法 document.onkeydown = function(e) { if (!e) e = window.event;//火狐中是 window.event if (( ...
- 2019 SDN第3次上机作业
0.报文类型与含义 1.Controller-to-Switch 报文 Cortoller-to-Switch是由控制器初始化并下发给交换机的报文类型,其可能会要求交换机回复对应的报文,此类型报文 ...
- 记一次edusoho问题
问题描述:Edusoho如何迁移到本地windows或另外一台Linux服务器上 解决问题步骤: 1.参考官方文档官方文档地址如下:http://www.qiqiuyu.com/my/course/3 ...
- 第09组 Alpha冲刺(2/4)
队名:软工9组 组长博客:https://www.cnblogs.com/cmlei/ 作业博客:http://edu.cnblogs.com/campus/fzu/SoftwareEngineeri ...