【问题标题】:How to ensure uniqueness in create_or_update without db level unique constraint in Django如何在没有 Django 中的数据库级别唯一约束的情况下确保 create_or_update 的唯一性
【发布时间】:2020-03-30 09:44:08
【问题描述】:

我正在使用 django 1.10 和 MySQL 5.7。

我有一个对多列有 unique_together 约束的表。但是这些列中很少有可以为空的。因此,对于任何这些字段中的空条目,都不能确保 DB 级别的唯一性。

我正在使用 create_or_update 方法来确保应用程序级别的行的唯一性。但是在竞争条件下,即使这样也不能确保唯一性,因为系统是水平扩展的,并且多个进程同时尝试调用 create_or_update 函数。

我认为这对于大多数大规模服务来说应该是一个非常正常的用例。我们如何解决这个问题?

根据我的想法,我的选择可以是:

  1. 保存字符串而不是保持条目可为空。 (但它是一个外键字段)。
  2. 根据唯一性列的字段保存格式化字符串并检查其唯一性。

我觉得这两个选项都不直观。这里通常遵循的最佳做法是什么?

【问题讨论】:

    标签: mysql django concurrency thread-safety scalability


    【解决方案1】:

    您的选择不可行:

    1. 如果您有如您所说的外键列,您将无法将列值设置为字符串。反正生成字符串不是个好办法

    2. 使用列的组合生成字符串可能在某些情况下,当您在同一列中具有相同值而在另一列中具有 null 时,您将生成不唯一的字符串。可能你会想在你的字符串生成中添加一个随机键或其他东西,但这会生成唯一的字符串但会出错,因为唯一的行将是“不同的”

    在某些情况下,django 中的文本字段不是 NULL,是空字符串,除非你指定 null=True,无论如何,你应该这样做:)

    在我看来你应该分析你的模型的业务规则,可能你选错了字段是唯一的。

    如果您在应用级别进行功能检查,您需要指定它是一个事务,因为它可能引发错误

    【讨论】:

      【解决方案2】:

      如果业务规则和数据库规划没有错误,另一种方法是在模型中自定义验证。

      例如模型内部:

      def clean(self):
          """
          Select model objects but exclude the ones that has null on some fields
          """
          conflicting_instance = Models.objects.filter(
              relation_field=self.relation_field).exclude(field=None)
          if self.id:
              """
              This instance has already been saved, so it need to be filtered
              """
              conflicting_instance = conflicting_instance.exclude(pk=self.id)
      
          conflicting_list = [conflicting_instance.exists(),]
      
          if True in conflicting_list:
              """
              Return an error message if any of the validations is True
              """
              if conflicting_list[0]:
                  raise ValidationError("""custom error.""")
          else:
              self.is_cleaned = True
      
      def save(self):
          """
          If everything if clean, save it
          """
          if self.is_cleaned is True:
              super(Model, self).save()
          else:
              pass
      

      【讨论】:

        猜你喜欢
        • 2011-02-07
        • 2017-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多