本篇笔记主要介绍Django的一些实例方法。什么是例子,我们知道通过filter()的一些过滤方法,得到QuerySet,而QuerySet取的是单条数据,通过索引得到的单条数据,或者first()或者last()是一个模型的实例。接下来要介绍的是这个单例的一些方法。save()的继承操作从db刷新,更新实例数据自增主键指定字段从数据库更新save()1、save()的继承操作对于一个模型,我们可以通过save()创建一条数据,例如:fromblog.modelsimportBlogblog=Blog(name="blog_1",tagline="tagline_1")blog.save()对于上面的博客,我们称它为Blog的一个实例。我们可以通过继承来覆盖原来的save()方法,然后添加一些我们需要的操作,比如打印日志,发送提醒等,方法如下:classBlog(models.Model):name=models.CharField(max_length=100)tagline=models.TextField()defsave(self,*args,**kwargs):print("save")super(Blog,self).save(*args,**kwargs)这样,当我们对Blog数据进行save()时,可以看到控制台会输出“save”的记录。另外,Django的文档提出了在模型中定义一个类方法的方法,可以方便我们处理数据:classBlog(models.Model):name=models.CharField(max_length=100)tagline=models.TextField()@classmethoddefcreate(cls,name,tagline):blog=cls(name=name,tagline=tagline)print("getanunsavedBloginstance")returnblog然后调用这个方法,传入参数,就可以得到一个未保存的Blog实例实例:fromblog.modelsimportBlogblog=Blog.create(name='test_create',tagline='test_tagline')blog.save()注:当我们执行create()方法时,程序还没有操作数据库,刚拿到一个未保存的实例,我们还需要执行save()操作保存到数据库中。除了这个方法,还有一个官方文档推荐的方法,就是使用manager。我们将在接下来的几篇笔记中介绍它的用法。这里只是一个演示:classBlogManager(models.Manager):defcreate_blog(self,name,tagline):blog=self.create(name=name,tagline=tagline)#dosomethingwiththeblogprint("getanunsavedBloginstance")returnblogclassBlog(models.Model):name=models.CharField(max_length=100)tagline=models.TextField()objects=BlogManager()需要注意的是这里调用了create()方法,所以直接保存到数据库中,不需要执行save()方法。2.refreshfromdb,从数据库中更新实例数据的方法是refresh_from_db(),用于从数据库中获取实例数据的最新值。blog=Blog.objects.first()#其他地方可能会对博客数据做一些改动#然后从数据库中拉取最新的博客数据blog.refresh_from_db()这个操作我在写单元测试的时候经常用到,比如afteraAfter一系列的操作,你要查看这个obj的数据有没有变化。在这种情况下,您可以使用此功能。下面说说refresh_from_db()函数的性能。refresh_from_db()的底层函数也是使用了get()方法,所以使用refresh_from_db()和get(pk=xx)在性能上可能差别不大,但是refresh_from_db()更加简洁。3.自增主键如果我们没有为模型设置PrimaryKey,系统会自动将自增主键的字段设置为模型的id。创建数据时,如果不指定该字段,系统会自动为其赋值。而当我们要复制一条数据记录时,可以将id字段设置为None,然后save(),系统会把它当作一条新数据,从而自动保存为新数据,并赋值给id字段。b=Blog.objects.first()b.id=Noneb.save()b.id4.指定字段更新save()假设有一个TestModel,有一个number字段,我们要对它进行+1操作,大概行为可能如下:obj=TestModel.objects.get(id=1)obj.number+=1obj.save()我们也可以使用F()函数稍微快一点,避免竞争(竞争意味着,Other进程也可以使用此数据):fromdjango.db.modelsimportFobj=TestModel.objects.get(id=1)obj.number=F('number')+1obj.save()指定要保存的字段简单地使用save()操作可能会导致问题。比如我们在某个地方获取了一条数据,修改了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()那么这个时候,因为已经从数据库中获取了博客数据,再次执行save()会保存之前获取的数据,这样会导致在此期间对标语字段进行的更新操作恢复。所以这个时候为了避免这种情况,我们在save()的时候指定我们要更新的字段来保存数据:blog.name="test_1"blog.save(update_fields=["name"])上面的这是第一个note的全部内容,下一个note会介绍manager的用法。
