Transaction.atomic 同时重写 Django 模型中的 save() 方法?

Chi*_*fir 2 python django overriding transactions python-3.x

我正在覆盖save()模型中的默认方法,并在那里创建一个相关的模型实例:

def save(self, *args, **kwargs):
    super().save(*args, **kwargs)
    parent_folder = None
    if self.parent:
        parent_folder = self.parent.task_folders.all().first()

    folder, created = Folder.objects.get_or_create(
        project=self.project,
        task=self,
        parent=parent_folder,
        defaults={'name': self.name,
                  'project': self.project,
                  'task': self,
                  'creator': self.creator,
                  'parent': parent_folder,
                  'is_root': True
                  })
Run Code Online (Sandbox Code Playgroud)

问题是 - 我应该transaction.atomic在这里使用吗?它如何与save()方法一起工作?

小智 5

不,您不需要在Django 模型中显式使用原子事务(例如“@transaction.atomic”“with transaction.atomic():”)重写“save()”,因为原子事务隐式用于重写“save” ()“默认情况下。

使用PostgreSQL,我尝试了原子事务是否默认隐式用于重写的“save()”,或者不使用下面的代码。* “SELECT”、“INSERT”、“UPDATE”和“DELETE”查询由“models.py”覆盖的“save()”中的“Animal”类代码运行,如下所示:

# "store/models.py"

from django.db import models

class Animal(models.Model):
    name = models.CharField(max_length=30)

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    
    def save(self, *args, **kwargs):
        
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" query

    def __str__(self):
        return self.first_name + " " + self.last_name
Run Code Online (Sandbox Code Playgroud)

然后,我添加一个人来运行“Person”类重写的“save()”,如下所示。*实际上,“John Smith”这个人没有被添加,因为重写的“save()”没有“super().save(*args, **kwargs)”

在此输入图像描述

现在,在“BEGIN”和“COMMIT”查询之间,“SELECT”、“INSERT”、“UPDATE”和“DELETE”查询由覆盖的“save()”中的“Animal”类代码运行。因此,默认情况下,原子事务隐式用于重写的 save()。*下面这些日志是PostgreSQL的查询日志。您可以检查在 PostgreSQL 上,如何使用事务查询(例如“BEGIN”和“COMMIT”)记录 SQL 查询

在此输入图像描述

此外,在重写的“save()”末尾,我添加了“super().save(*args, **kwargs)”,它运行“INSERT”查询,如下所示:

# "store/models.py"

from django.db import models

class Animal(models.Model):
    name = models.CharField(max_length=30)

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    
    def save(self, *args, **kwargs):
        
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" query

        super().save(*args, **kwargs) # For "INSERT" query

    def __str__(self):
        return self.first_name + " " + self.last_name
Run Code Online (Sandbox Code Playgroud)

然后,我添加一个人来运行“Person”类重写的“save()”,如下所示。*这次,添加了“John Smith”这个人,因为重写的“save()”“super().save(*args, **kwargs)”

在此输入图像描述

现在,“INSERT”查询由“super().save(*args, **kwargs)”在“BEGIN”和“COMMIT”查询之间的“DELETE”查询之后运行,如下所示:

在此输入图像描述

接下来,在重写的“save()”的开头,我添加“super().save(*args, **kwargs)”,它运行“INSERT”查询,如下所示:

# "store/models.py"

from django.db import models

class Animal(models.Model):
    name = models.CharField(max_length=30)

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    
    def save(self, *args, **kwargs):

        super().save(*args, **kwargs) # For "INSERT" query
        
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" query

    def __str__(self):
        return self.first_name + " " + self.last_name
Run Code Online (Sandbox Code Playgroud)

然后,我添加一个人来运行“Person”类重写的“save()”,如下所示。*这次,添加了“John Smith”这个人,因为重写的“save()”“super().save(*args, **kwargs)”

在此输入图像描述

现在,“INSERT”查询由“super().save(*args, **kwargs)”在“BEGIN”和“COMMIT”查询之间的“SELECT”查询之前运行,如下所示:

在此输入图像描述

接下来,对于重写的“save()”,我放置“@transaction.atomic”装饰器,如下所示:

# "store/models.py"

from django.db import models

class Animal(models.Model):
    name = models.CharField(max_length=30)

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    
    @transaction.atomic # Here
    def save(self, *args, **kwargs):
        
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" query

    def __str__(self):
        return self.first_name + " " + self.last_name
Run Code Online (Sandbox Code Playgroud)

或者,对于覆盖的“save()”,我放置“with transaction.atomic():”,如下所示:

# "store/models.py"

from django.db import models

class Animal(models.Model):
    name = models.CharField(max_length=30)

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    
    def save(self, *args, **kwargs):
        
        with transaction.atomic(): # Here

            animal = Animal.objects.all() # For "SELECT" query
            print(animal) # Needed to run "SELECT" query

            Animal(name='Dog').save() # For "INSERT" query

            Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

            Animal.objects.filter(name="Cat").delete() # For "DELETE" query

    def __str__(self):
        return self.first_name + " " + self.last_name
Run Code Online (Sandbox Code Playgroud)

然后,我添加一个人来运行“Person”类重写的“save()”,如下所示:

在此输入图像描述

现在,“SAVEPOINT”和“RELEASE SAVEPOINT”查询分别在“BEGIN”查询之后和“DELETE”查询之后在“BEGIN”和“COMMIT ”之间由“@transaction.atomic”装饰器“with transaction.atomic():”运行”查询如下图:

在此输入图像描述

接下来,对于重写的“save()”,如下所示:

# "store/models.py"

from django.db import models

class Animal(models.Model):
    name = models.CharField(max_length=30)

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    
    def save(self, *args, **kwargs):
        
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" query

    def __str__(self):
        return self.first_name + " " + self.last_name
Run Code Online (Sandbox Code Playgroud)

我将'ATOMIC_REQUESTS': True放入“settings.py”中的PostgreSQL 设置

# "core/settings.py"

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.postgresql',
        'NAME':'postgres',
        'USER':'postgres',
        'PASSWORD':'admin',
        'HOST':'localhost',
        'PORT':'5432',
        'ATOMIC_REQUESTS': True, # Here
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我添加一个人来运行“Person”类重写的“save()”,如下所示:

在此输入图像描述

现在,“SAVEPOINT”和“RELEASE SAVEPOINT”查询由“ATOMIC_REQUESTS”运行分别在“Animal”类代码运行的“SELECT”查询之前和“COMMIT”查询之前为 True ,并且在之间添加了2 个蓝色的“SELECT”查询BEGIN”和“COMMIT”查询如下所示:

在此输入图像描述

接下来,对于重写的“save()”,我放置了“@transaction.atomic”装饰器“with transaction.atomic():”,如下所示:

# "store/models.py"

from django.db import models

class Animal(models.Model):
    name = models.CharField(max_length=30)

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    
    @transaction.atomic # Here
    def save(self, *args, **kwargs):
        
        with transaction.atomic(): # Here

            animal = Animal.objects.all() # For "SELECT" query
            print(animal) # Needed to run "SELECT" query

            Animal(name='Dog').save() # For "INSERT" query

            Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

            Animal.objects.filter(name="Cat").delete() # For "DELETE" query

    def __str__(self):
        return self.first_name + " " + self.last_name
Run Code Online (Sandbox Code Playgroud)

而且,我还在“settings.py”中将'ATOMIC_REQUESTS': True设置为我的 PostgreSQL 设置,如下所示:

# "core/settings.py"

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.postgresql',
        'NAME':'postgres',
        'USER':'postgres',
        'PASSWORD':'admin',
        'HOST':'localhost',
        'PORT':'5432',
        'ATOMIC_REQUESTS': True, # Here
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我添加一个人来运行“Person”类重写的“save()”,如下所示:

在此输入图像描述

现在,在“BEGIN”和“COMMIT”查询之间,3个“SAVEPOINT”和3个“RELEASE SAVEPOINT”查询由“@transaction.atomic”装饰器运行,“with transaction.atomic():”“ATOMIC_REQUESTS”:True和添加了2 个蓝色的“SELECT”查询,如下所示:

在此输入图像描述

另外,再次使用PostgreSQL,我还通过下面的代码尝试了默认情况下是否将原子事务隐式用于视图。* “SELECT”、“INSERT”、“UPDATE”和“DELETE”查询由“views.py”“test()”视图中的“Animal”类代码运行,如下所示:

# "store/views.py"

from django.http import HttpResponse
from .models import Animal

def test(request):

    animal = Animal.objects.all() # For "SELECT" query
    print(animal) # Needed to run "SELECT" query

    Animal(name='Dog').save() # For "INSERT" query

    Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

    Animal.objects.filter(name="Cat").delete() # For "DELETE" 

    return HttpResponse("Test")
Run Code Online (Sandbox Code Playgroud)

并且,这是下面的“urls.py”

# "store/urls.py"

from django.urls import path
from . import views

app_name = "store"

urlpatterns = [
    path('test/', views.test, name="test"),
]
Run Code Online (Sandbox Code Playgroud)

然后,我打开url“http://localhost:8000/store/test/”来运行“test”视图,如下所示:

在此输入图像描述

现在,在“BEGIN”和“COMMIT”查询之间,“test()”视图中的“Animal”类代码仅运行“DELETE”查询。因此,默认情况下,原子事务不会隐式用于视图。*下面这些日志是PostgreSQL的查询日志

在此输入图像描述

接下来,对于“test()”视图,我放置“@transaction.atomic”装饰器,如下所示:

# "store/views.py"

from django.http import HttpResponse
from .models import Animal

@transaction.atomic # Here
def test(request):
    
    animal = Animal.objects.all() # For "SELECT" query
    print(animal) # Needed to run "SELECT" query

    Animal(name='Dog').save() # For "INSERT" query

    Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

    Animal.objects.filter(name="Cat").delete() # For "DELETE" 

    return HttpResponse("Test")
Run Code Online (Sandbox Code Playgroud)

或者,对于“test()”视图,我输入“with transaction.atomic():”,如下所示:

# "store/views.py"

from django.http import HttpResponse
from .models import Animal

def test(request):

    with transaction.atomic(): # Here
    
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" 

        return HttpResponse("Test")
Run Code Online (Sandbox Code Playgroud)

或者,对于“test()”视图,我将'ATOMIC_REQUESTS': True放入“settings.py”中的PostgreSQL 设置,如下所示:

# "core/settings.py"

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.postgresql',
        'NAME':'postgres',
        'USER':'postgres',
        'PASSWORD':'admin',
        'HOST':'localhost',
        'PORT':'5432',
        'ATOMIC_REQUESTS': True, # Here
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我打开url“http://localhost:8000/store/test/”来运行“test”视图,如下所示:

在此输入图像描述

现在,在“BEGIN”和“COMMIT”查询之间,“SELECT”、“INSERT”、“UPDATE”和“DELETE”查询由“test()”视图中的“Animal”类代码运行。现在,原子事务可以工作了:

在此输入图像描述

接下来,对于“test()”视图,我放置了“@transaction.atomic”装饰器“with transaction.atomic():”,如下所示:

# "store/views.py"

from django.http import HttpResponse
from .models import Animal

@transaction.atomic # Here
def test(request):
    
    with transaction.atomic(): # Here
        
        animal = Animal.objects.all() # For "SELECT" query
        print(animal) # Needed to run "SELECT" query

        Animal(name='Dog').save() # For "INSERT" query

        Animal.objects.filter(name="Dog").update(name="Cat") # For "UPDATE" query

        Animal.objects.filter(name="Cat").delete() # For "DELETE" 

        return HttpResponse("Test")
Run Code Online (Sandbox Code Playgroud)

而且,我还在“settings.py”中将'ATOMIC_REQUESTS': True设置为我的 PostgreSQL 设置,如下所示:

# "core/settings.py"

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.postgresql',
        'NAME':'postgres',
        'USER':'postgres',
        'PASSWORD':'admin',
        'HOST':'localhost',
        'PORT':'5432',
        'ATOMIC_REQUESTS': True, # Here
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我打开url“http://localhost:8000/store/test/”来运行“test”视图,如下所示:

在此输入图像描述

现在,在“BEGIN”和“COMMIT”查询之间,运行2 个“SAVEPOINT”和 2 个“RELEASE SAVEPOINT”查询,如下所示:

在此输入图像描述