【问题标题】:Django Model: Default method for field called multiple timesDjango模型:多次调用字段的默认方法
【发布时间】:2023-03-09 18:50:02
【问题描述】:

我有以下两种型号(仅供测试):

class IdGeneratorModel(models.Model):

    table = models.CharField(primary_key=True, unique=True,
                             null=False, max_length=32)
    last_created_id = models.BigIntegerField(default=0, null=False,
                                             unique=False)

    @staticmethod
    def get_id_for_table(table: str) -> int:
        try:
            last_id_set = IdGeneratorModel.objects.get(table=table)
            new_id = last_id_set.last_created_id + 1
            last_id_set.last_created_id = new_id
            last_id_set.save()
            return new_id
        except IdGeneratorModel.DoesNotExist:
            np = IdGeneratorModel()
            np.table = table
            np.save()
            return IdGeneratorModel.get_id_for_table(table)

class TestDataModel(models.Model):

    class Generator:
        @staticmethod
        def get_id():
            return IdGeneratorModel.get_id_for_table('TestDataModel')

    id = models.BigIntegerField(null=False, primary_key=True,
                                editable=False, auto_created=True,
                                default=Generator.get_id)
    data = models.CharField(max_length=16)

现在我使用普通的 Django 管理站点来创建一个新的测试数据集元素。我所期望的(也许我在这里错了)是,在将新数据集保存到数据库时,方法 Generator.get_id() 恰好被调用一次。但真正发生的是,Generator.get_id() 方法被调用了 3 次:

  • 第一次点击管理区域中的“添加测试数据集”按钮时
  • 此后不久第二次(用户端没有额外的交互)
  • 第三次终于保存新数据集时

第一次可能没问题:这将是预先填写在表单字段中的值。由于我的表单中没有显示主键字段,这可能是不必要的调用。

第三次也很清楚:保存前就完成了。当它真的需要时。

上面的代码只是一个例子,对我来说是一个测试。在实际项目中,我必须向远程系统询问 ID,而不是从另一个表模型。但是每当我查询该系统时,传递的 ID 就会被锁定在那里 - 就像 get_id_for_table() 方法计数一样。

我确信只有在真正需要时才能从方法中获取 ID 有更好的方法 - 该方法应该只调用一次 - 在插入新数据集时。知道如何实现吗?

忘记了版本:它是 Python 3.4 上的 Django 1.8.5。

【问题讨论】:

  • 那不是原子的 (save()),当你意识到你的 id 被复制时,你将陷入痛苦的世界。数据库又做自动编号有什么问题?
  • 这只是一个测试示例。在实际项目中,我从远程服务获取 ID。该服务当然会关心每个 ID 只提供一次。但我需要确保调用服务的方法只为单个新数据集调用一次。
  • 我过去遇到过signals 两次调用我的代码的问题,调试起来有点痛苦,但不用担心。 PDB 来救援,或者ipdb 更好。 pip install ipdb 然后在你的get_id_for_table() 中添加import ipdb; ipdb.set_trace() 然后看看你的控制台并等待休息,输入where 你会看到它是如何以及为什么被调用的。
  • 您是 Java 程序员吗?这真的不是你编写 Python 的方式。

标签: python django django-models django-orm


【解决方案1】:

这不是您问题的答案,但可能是您问题的解决方案

我认为这个问题非常复杂。特别是因为您想要一个跨越 web 服务调用和数据库插入的事务......在这种情况下我会使用:在本地生成一个 uuid。这个值几乎可以保证在 4d 世界中是唯一的(时间 + 位置)并将其用作 id。稍后,当保存完成后,与您的远程服务同步。

【讨论】:

  • 事实上,这是我目前 B 计划的一部分。
猜你喜欢
  • 2012-08-09
  • 1970-01-01
  • 2011-06-04
  • 2010-10-19
  • 2018-10-20
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
相关资源
最近更新 更多