Django model重写save方法及update踩坑详解

 更新时间:2020年07月27日 17:12:20   作者:ops-coffee  
这篇文章主要介绍了Django model重写save方法及update踩坑详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

一个非常实用的小方法

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

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

以上方式比较简单,容易理解,但随之又带来了麻烦,我们需在所有接收数据的地方都要去校验,那么有没有更加优雅的方式呢?如果你看过我之前的文章『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_save和post_save也不会被调用。与save()类似的还有model的delete()方法,当批量删除的时候,同样不会调用model的delete()方法,但delete是可以使用pre_delete或post_delete信号的

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

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

补充知识:django model save方法对未更改的字段依然进行了保存

看代码吧~

obj = Obj.objects.get(id=1)
print obj.name #此时name的值假定为'abc'
 
def handler(oid):
  obj = Obj.objects.get(id=oid)
  obj.name = '123'
  obj.save()
handler(obj.id)
obj.age = 10
obj.save()
print obj.name 

最终的name结果依然为'abc'。save()保存时,虽然没有更改其它字段,但依然会将内存中的值,再次存入数据库,子函数和其它进程更改的值会被覆盖。

以上这篇Django model重写save方法及update踩坑详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 用Python实现一个打字速度测试工具来测试你的手速

    用Python实现一个打字速度测试工具来测试你的手速

    有很多小伙伴们都苦恼自己手速不够,今天特地整理了这篇文章,教你用Python实现一个打字测试工具来测试你的打字速度,文中有非常详细的代码示例,对想练手速的小伙伴们很有用哦,需要的朋友可以参考下
    2021-05-05
  • python 爬虫出现403禁止访问错误详解

    python 爬虫出现403禁止访问错误详解

    这篇文章主要介绍了 python 爬虫解决403禁止访问错误的相关资料,需要的朋友可以参考下
    2017-03-03
  • python数据可视化绘制火山图示例

    python数据可视化绘制火山图示例

    这篇文章主要为大家介绍了python数据可视化绘制火山图示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Python实战项目之MySQL tkinter pyinstaller实现学生管理系统

    Python实战项目之MySQL tkinter pyinstaller实现学生管理系统

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用MySQL、tkinter、 pyinstaller实现一个学生管理系统,大家可以通过案例查缺补漏,提升水平
    2021-10-10
  • windows端python版本管理工具pyenv-win安装使用

    windows端python版本管理工具pyenv-win安装使用

    这篇文章主要介绍了如何通过git方式下载和配置pyenv-win,包括下载、克隆仓库、配置环境变量等步骤,同时还详细介绍了如何使用pyenv-win管理Python版本,需要的朋友可以参考下
    2025-01-01
  • Python中的函数作用域

    Python中的函数作用域

    在python中,一个函数就是一个作用域。这篇文章重点给大家介绍python中的函数作用域,感兴趣的朋友一起看看吧
    2018-05-05
  • Python 字符串类型列表转换成真正列表类型过程解析

    Python 字符串类型列表转换成真正列表类型过程解析

    这篇文章主要介绍了Python 字符串类型列表转换成真正列表类型过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • python matplotlib各种画图

    python matplotlib各种画图

    这篇文章主要介绍了python matplotlib各种画图,matplotlib是一种优秀的python数据可视化第三方库,使用matpltlib库画图时,先将它引入,加载里面的pyplot,并命名为plt,然后使用plot函数画图<BR>,下面一起来了解更详细内容吧
    2021-12-12
  • 收集的几个Python小技巧分享

    收集的几个Python小技巧分享

    这篇文章主要介绍了收集的几个Python小技巧分享,如获得当前机器的名字、获取当前工作路径、获取系统的临时目录等,需要的朋友可以参考下
    2014-11-11
  • Django自定义认证方式用法示例

    Django自定义认证方式用法示例

    这篇文章主要介绍了Django自定义认证方式用法,结合实例形式分析了Django自定义认证的创建、设置及功能实现技巧,需要的朋友可以参考下
    2017-06-06

最新评论