Python Django记录锁定和原子事务

Python Django记录锁定和原子事务,python,django,postgresql,mariadb,Python,Django,Postgresql,Mariadb,我试图在我正在做的项目中实现一些关键的更新。 总之,我需要从一个工作文件中获取信息,该文件进行进一步处理,然后将其更新为最终文件。此信息来自不同的来源,因此最好在中间文件上执行此操作,然后将其写入最终文件 我的问题是,一些详图线数据在途中丢失。我在下面的文件中复制了这个问题,以消除任何积垢。只需在manage.py shell中运行这些函数。这在Mariadb和Postgresql中都有体现 有没有更好的方法来实现这一点而不是解决办法 models.py: import random from

我试图在我正在做的项目中实现一些关键的更新。 总之,我需要从一个工作文件中获取信息,该文件进行进一步处理,然后将其更新为最终文件。此信息来自不同的来源,因此最好在中间文件上执行此操作,然后将其写入最终文件

我的问题是,一些详图线数据在途中丢失。我在下面的文件中复制了这个问题,以消除任何积垢。只需在manage.py shell中运行这些函数。这在Mariadb和Postgresql中都有体现

有没有更好的方法来实现这一点而不是解决办法

models.py:

import random
from decimal import Decimal

from django.db import models, transaction


class Head(models.Model):
    name = models.CharField(max_length=20, default="")
    h1_text = models.CharField(max_length=20, default="")

    def update(self):
        tmp1 = Tmp1Head()
        tmp1.name = self.h1_text
        tmp1.save()
        for line in self.head_lines.all():
            tl1 = Tmp1Line()
            tl1.head = tmp1
            tl1.data_text = line.data_text
            tl1.t1_data = line.t1_data
            tl1.t2_data = Decimal(random.random())
            tl1.save()

        with transaction.atomic():
            transaction.on_commit(tmp1.update)

        tmp1.delete()  # All fine - remove this work transaction.
        return True


class Line(models.Model):
    head = models.ForeignKey(Head, on_delete=models.CASCADE, related_name='head_lines')
    data_text = models.CharField(max_length=20, default="")
    t1_data = models.DecimalField(max_digits=12, decimal_places=2)


class Tmp1Head(models.Model):
    name = models.CharField(max_length=20, default="")

    def update(self):
        tmp2 = Tmp2Head()
        tmp2.name = self.name
        tmp2.save()
        for line in self.tmp1_lines.all():
            tl2 = Tmp2Line()
            tl2.head = tmp2
            tl2.data_summary = line.data_text
            tl2.final_data = line.t1_data * line.t2_data
            tl2.save()


class Tmp1Line(models.Model):
    head = models.ForeignKey(Tmp1Head, on_delete=models.CASCADE, related_name='tmp1_lines')
    data_text = models.CharField(max_length=20, default="")
    t1_data = models.DecimalField(max_digits=12, decimal_places=2)
    t2_data = models.DecimalField(max_digits=12, decimal_places=2)


class Tmp2Head(models.Model):
    name = models.CharField(max_length=20, default="")


class Tmp2Line(models.Model):
    head = models.ForeignKey(Tmp2Head, on_delete=models.CASCADE, related_name='tmp2_lines')
    data_summary = models.CharField(max_length=20, default="")
    final_data = models.DecimalField(max_digits=12, decimal_places=2)
# with transaction.atomic():
# transaction.on_commit(tmp1.update)
tmp1.update()
视图.py

from .models import *


def populate():
    Head.objects.all().delete()
    Tmp1Head.objects.all().delete()
    Tmp2Head.objects.all().delete()

    head = Head.objects.create(name="test", h1_text="test text")
    for tmp in range(1, 5):
        Line.objects.create(head=head,
                            data_text=f"data line:{tmp}",
                            t1_data=tmp)


def test1(): # all fine but no locking.
    batch = Head.objects.first()
    batch.update()


def test2():  # record locking but the data lines get lost in the final table.
    with transaction.atomic():
        batch = Head.objects.select_for_update().first()
        batch.update()


def test3():  # record locking, no data lost, but the temp data is not removed.
    """
    Same as test 2 but remove the below line from update function in the Head model.
        tmp1.delete()  # All fine - remove this work transaction.
    """
    with transaction.atomic():
        batch = Head.objects.select_for_update().first()
        batch.update()

为了解决这个问题,我去掉了保存点,现在一切似乎都好了。 它应该是安全的,因为只有程序才能访问临时文件

我将其从models.py中删除:

import random
from decimal import Decimal

from django.db import models, transaction


class Head(models.Model):
    name = models.CharField(max_length=20, default="")
    h1_text = models.CharField(max_length=20, default="")

    def update(self):
        tmp1 = Tmp1Head()
        tmp1.name = self.h1_text
        tmp1.save()
        for line in self.head_lines.all():
            tl1 = Tmp1Line()
            tl1.head = tmp1
            tl1.data_text = line.data_text
            tl1.t1_data = line.t1_data
            tl1.t2_data = Decimal(random.random())
            tl1.save()

        with transaction.atomic():
            transaction.on_commit(tmp1.update)

        tmp1.delete()  # All fine - remove this work transaction.
        return True


class Line(models.Model):
    head = models.ForeignKey(Head, on_delete=models.CASCADE, related_name='head_lines')
    data_text = models.CharField(max_length=20, default="")
    t1_data = models.DecimalField(max_digits=12, decimal_places=2)


class Tmp1Head(models.Model):
    name = models.CharField(max_length=20, default="")

    def update(self):
        tmp2 = Tmp2Head()
        tmp2.name = self.name
        tmp2.save()
        for line in self.tmp1_lines.all():
            tl2 = Tmp2Line()
            tl2.head = tmp2
            tl2.data_summary = line.data_text
            tl2.final_data = line.t1_data * line.t2_data
            tl2.save()


class Tmp1Line(models.Model):
    head = models.ForeignKey(Tmp1Head, on_delete=models.CASCADE, related_name='tmp1_lines')
    data_text = models.CharField(max_length=20, default="")
    t1_data = models.DecimalField(max_digits=12, decimal_places=2)
    t2_data = models.DecimalField(max_digits=12, decimal_places=2)


class Tmp2Head(models.Model):
    name = models.CharField(max_length=20, default="")


class Tmp2Line(models.Model):
    head = models.ForeignKey(Tmp2Head, on_delete=models.CASCADE, related_name='tmp2_lines')
    data_summary = models.CharField(max_length=20, default="")
    final_data = models.DecimalField(max_digits=12, decimal_places=2)
# with transaction.atomic():
# transaction.on_commit(tmp1.update)
tmp1.update()