一个非常实用的小方法

试想一下,Django中如果我们想对保存进数据库的数据做校验,有哪些实现的方法?

我们可以在view中去处理,每当view接收请求,就对提交的数据做校验,校验不通过直接返回错误,不写数据库,校验通过再调用createupdate方法写入数据库

以上方式比较简单,容易理解,但随之又带来了麻烦,我们需在所有接收数据的地方都要去校验,那么有没有更加优雅的方式呢?如果你看过我之前的文章『Django使用Signals监测model字段变化发送通知』]就能想到可以通过signals信号来处理,添加一个pre_save的信号,每当数据库数据变更前都会触发pre_save方法,可以在这里进行校验,免去了view中多个地方校验的麻烦

而今天要说的并不是signals,而是另一种比较常用的做法:重写model的save方法

重写save方法

save方法的主要作用就是将一个对象保存到数据库。如果我们想在数据入库之前做一些处理,除了上边提到的signals之外,还可以通过重写save方法来实现。具体实现方式看下面这个例子

假如我们定义了model如下:

class TempTask(models.Model):
... exechost = models.CharField(max_length=64, default='localhost', verbose_name='执行主机')
execuser = models.ForeignKey(ExecUser, null=True, on_delete=models.PROTECT, db_constraint=False)

exechost默认为Localhost,execuser默认为空,现有需求:当exechost不为localhost时,他必须符合ip:port的格式,且execuser不能为空。这是一个比较复杂的校验方式,我们可以通过重写save方法来处理

class TempTask(models.Model):
... def save(self, *args, **kwargs):
if self.exechost and (self.exechost.strip() != 'localhost'):
if len(self.exechost.split(':')) != 2:
raise ValidationError('执行主机格式错误,应为ip:port格式') if not self.execuser:
raise ValidationError('当执行主机存在时执行用户不能为空') super().save(*args, **kwargs)

我们可以在save函数内执行各种自定义逻辑,但需要注意的是,最后必须要调用super().save()方法来保证执行了父类的save(),这样才能保证数据写入了数据库。

这样在当我们执行create语句插入数据的时候就会先去执行save中的校验方法进行校验了

TempTask.objects.create(**postdata)

update踩坑

就当我以为一切都要结束准备起身冲杯咖啡的时候,我发现新加数据可以正常进行校验,但更新数据却不行,更新的代码如下:

TempTask.objects.filter(id=pk).update(**postdata)

经过一番查找发现了问题所在,官方文档中有这么一句话

Unfortunately, there isn’t a workaround when creating or updating objects in bulk, since none of save(), pre_save, and post_save are called.

也就是说,当使用查询集批量更新对象时,将不会为每个对象调用save()方法,连pre_savepost_save也不会被调用。与save()类似的还有model的delete()方法,当批量删除的时候,同样不会调用model的delete()方法,但delete是可以使用pre_deletepost_delete信号的

解决这个问题的方法很简单,那就是将更新的代码换成下边这种,保证调用到save方法

_t = TempTask.objects.get(id=pk)
_t.__dict__.update(**postdata)
_t.save()

Django model重写save方法及update踩坑记录的更多相关文章

  1. CakePHP采用model的save方法更新数据所需查询

    采用model的save方法更新数据所需查询 1. 验证时候要确认是update 或者 create,以便使用对应规则 public $validate = array( 'field_name' = ...

  2. backbone Model调用save方法的时候提交方式

    horizon使用的是backbone框架,但是我们的后台api都是只接收post请求,请求的路径为/api/,根据backbone的官档解释: backbone的model.save方法会判断当前的 ...

  3. CentOS7.4安装MySQL踩坑记录

    CentOS7.4安装MySQL踩坑记录 time: 2018.3.19 CentOS7.4安装MySQL时网上的文档虽然多但是不靠谱的也多, 可能因为版本与时间的问题, 所以记录下自己踩坑的过程, ...

  4. google nmt 实验踩坑记录

       最近因为要做一个title压缩的任务,所以调研了一些text summary的方法.    text summary 一般分为抽取式和生成式两种.前者一般是从原始的文本中抽取出重要的word o ...

  5. manjaro xfce 18.0 踩坑记录

    manjaro xfce 18.0 踩坑记录 1 简介1.1 Manjaro Linux1.2 开发桌面环境2 自动打开 NumLock3 系统快照3.1 安装timeshift3.2 使用times ...

  6. ubuntu 下安装docker 踩坑记录

    ubuntu 下安装docker 踩坑记录 # Setp : 移除旧版本Docker sudo apt-get remove docker docker-engine docker.io # Step ...

  7. SpringBoot + Shiro + shiro.ini 的踩坑记录

    0.写在前面的话 好久没写博客了,诶,好多时候偷懒直接就抓网上的资料丢笔记里了,也就没有自己提炼,偷懒偷懒.然后最近参加了一个网络课程,要交作业的那种,为了能方便看下其他同学的作业,就写了个爬虫把作业 ...

  8. 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密

    你真的了解字典(Dictionary)吗?   从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...

  9. SpringBoot+SpringSecurity+Thymeleaf认证失败返回错误信息踩坑记录

    Spring boot +Spring Security + Thymeleaf认证失败返回错误信息踩坑记录 步入8102年,现在企业开发追求快速,Springboot以多种优秀特性引领潮流,在众多使 ...

随机推荐

  1. 邮件退信“Remote Server returned '420 4.2.0 Recipient deferred because there is no Mdb'”

    标题是一个近期遇到的NDR 对于Exchange运维工作者,NDR通常给了我们较为清晰的排错方向,我们先看一下退信的原因, 我的一台MailBox报错“远程服务器返回‘420 4.2.0’接受延迟,因 ...

  2. CSS3 制作正方体

    一.预备知识 变形属性 2D变形属性 transform:他是css3中的变形属性: 通过transform(变形) 来实现2d 或者3d 转换,其中2d 有,缩放 scale(x, y) ,移动 t ...

  3. Python的深浅copy详解

    Python的深浅copy详解 目录 Python的深浅copy详解 一.浅copy的原理 1.1 浅copy的定义 1.2 浅copy的方法 二.深copy的原理 2.1 深copy的定义 2.2 ...

  4. vue单页应用和和多页应用的区别

    个人见解如下: 单页面应用(SinglePage Web Application  )简称:SPA 多页面应用 (MultiPage Application) 简称:MPA 组成一个外壳和多个页面片段 ...

  5. 提高万恶的KPI,切忌要避开这六个低效的编程习惯

    作者:程序员小跃 Slogan:当你的才华还无法撑起你的野心时,那应该静下心来好好学习 上次的翻译,引起了很大的反响,大家都想知道自己和高级工程师的差距,看了我的文章,是不是都在默默地做着比较呢?如果 ...

  6. F - Pearls HDU - 1300

    简单dp. 题目大意:有n种珍珠,这n种珍珠有不同的需求量,不同的价格,价格越高,质量越高,在购买每一种珍珠时,都需要在原来的基础上多买10个.也就是说如果需要买x种珍珠,那就要付x+10个的钱.每一 ...

  7. 视频+图文 String类干货向总结

    目录 一.字符串的介绍及视频讲解 二.字符串的两种创建方式 方法一:通过new创建 方法二:直接创建 三.字符串的长度获取:length()方法 四.使用 == 和equals()方法比较两个字符串 ...

  8. 不借助多余参数也可交换两个参数(c++,swap函数)

    利用a^a=0异或属性 [示例代码] #include<stdio.h> void data_swap(int &a,int &b){ a = a ^ b; b = a ^ ...

  9. vnpy源码阅读学习(9)回到OptionMaster

    回到OptionMaster 根据我们对APP调用的代码阅读,我们基本上知道了一个APP是如何被调用,那么我们回到OptionMaster学习下这个APP的实现. 看看结构 class OptionM ...

  10. 团队题目——TD课程通

    一.团队介绍 团队名称:精神小伙成双队 团队成员:冯静妃(博客地址:https://www.cnblogs.com/fengjingfei/) 李佳伟(博客地址:https://www.cnblogs ...