乐趣区

关于django:Django笔记十八之save函数的继承操作和指定字段更新等实例方法

这篇笔记次要介绍 Django 一些实例办法。

什么是 实例,咱们晓得通过 filter() 的一些筛选办法,失去的是 QuerySet,而 QuerySet 取单条数据,通过索引,或者 first() 或者 last() 等办法,失去的单条数据,就是一个 model 的实例。

咱们接下来要介绍的就是这种单条实例的一些办法。

  1. save() 的继承操作
  2. refresh from db,从数据库中更新实例数据
  3. 自增的主键
  4. 指定字段更新 save()

1、save() 的继承操作

对于一个 model,咱们能够通过 save() 的形式创立一条数据,比方:

from blog.models import Blog

blog = Blog(name="blog_1", tagline="tagline_1")
blog.save()

对于下面的 blog,咱们就称其为 Blog 的一个实例。

咱们能够通过继承笼罩原有的 save() 办法,而后新增一些咱们须要的操作,比方打印日志,发送揭示等。

办法如下:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()


    def save(self, *args, **kwargs):
        print("save")
        super(Blog, self).save(*args, **kwargs)

这样,咱们在对 Blog 数据进行 save() 操作的时候,就能够看到控制台会输入 “save” 的记录。

除此之外,Django 的文档提出了一种形式,在 model 中定义一个类办法,能够不便咱们对数据进行解决:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()


    @classmethod
    def create(cls, name, tagline):
        blog = cls(name=name, tagline=tagline)
        print("get an unsaved Blog instance")
        return blog

而后通过调用该办法,传入参数,能够失去一个未保留的实例:

from blog.models import Blog
blog = Blog.create(name='test_create', tagline='test_tagline')
blog.save()

留神: 在咱们执行 create() 办法的时候,程序还没有操作数据库,只是失去一个未保留的实例,咱们依然须要执行 save() 操作能力保留到数据库。

除了这种办法,还有一种官网文档更举荐的办法,就是应用 manager,这个的用法咱们在前面几篇笔记中波及,这里只做一个展现:

class BlogManager(models.Manager):
    def create_blog(self, name, tagline):
        blog = self.create(name=name, tagline=tagline)
        # do something with the blog
        print("get an unsaved Blog instance")
        return blog


class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()


    objects = BlogManager()

须要留神的是,这里调用的是 create() 办法,所以间接保留到了数据库,不必再执行 save() 办法了。

2、refresh from db,从数据库中更新实例数据

办法为 refresh_from_db()

作用为从数据库中获取实例数据的最新值。

blog = Blog.objects.first()

# 其余中央可能会对 blog 数据进行一些更改

# 而后从数据库中拉取 blog 的最新数据

blog.refresh_from_db()

这个操作我集体经常用在写单元测试,比方通过一系列操作之后,想要查看这个 obj 的数据有没有更改,这种状况下就能够应用这个函数。

说一下 refresh_from_db() 这个函数的性能问题,refresh_from_db() 的底层函数也是应用的 get() 办法

所以应用 refresh_from_db() 和 get(pk=xx) 这两者在性能上可能差异不会很大,然而 refresh_from_db() 则更为简洁。

3、自增的主键

如果咱们没有为 model 设置 PrimaryKey,那么零碎则会主动为 model 设置自增主键为 id 的字段,创立数据的时候,不指定该字段,零碎会主动为其赋值。

而当咱们想要复制一条数据记录的时候,咱们能够将 id 字段置为 None,而后 save(),零碎则会将其视为一条新数据,从而主动保留为新数据并为 id 字段赋值。

b = Blog.objects.first()
b.id = None
b.save()
b.id

4、指定字段更新 save()

假如有一个 TestModel,有一个 number 字段,咱们想要对其执行 +1 的操作,大略行为可能如下:

obj = TestModel.objects.get(id=1)
obj.number += 1
obj.save()

咱们也能够通过 F() 函数这种略微快一点和防止竞争的形式(竞争的意思是,其余的过程可能也在应用这条数据):

from django.db.models import F
obj = TestModel.objects.get(id=1)
obj.number = F('number') + 1
obj.save()

指定字段保留
单纯的应用 save() 操作可能会造成一个问题,比如说,咱们在某一个 get 了一条数据,对 name 字段进行了更改,但同时另一个过程对同一条数据也进行了更改,咱们对这条数据进行 save() 操作,那么就可能造成数据不统一的状况。

blog = Blog.objects.get(id=1)
blog.name = "test_1"

# 在这个期间,另一个过程对 tagline 字段进行了更改
# 假如该操作为 Blog.objects.filter(id=1).update(tagline="new_tagline")

# 而后执行 save() 操作
blog.save()

那么这个时候,blog 的数据因为曾经从数据库中获取了进去,再执行 save() 则会保留之前获取的数据,这样会导致在此期间对 tagline 字段进行的更新操作还原。

那么这个时候,为了防止这种状况产生,咱们在 save() 的时候指定咱们要更新的字段来保留数据:

blog.name = "test_1"
blog.save(update_fields=["name"])

以上就是本篇笔记全部内容,下一篇笔记将介绍 manager 的用法。

本文首发于自己微信公众号:Django 笔记。

原文链接:Django 笔记十八之 save 函数的继承操作和指定字段更新等实例办法

如果想获取更多相干文章,可扫码关注浏览:

退出移动版