【问题标题】:How to create model with 2 columns unique together and autoincrement?如何创建具有 2 列唯一且自动递增的模型?
【发布时间】:2021-01-20 09:08:28
【问题描述】:

我在 Django 的 Invoice 模型中有两列:

class Invoice(models.Model):
    use_in_migrations = True

    year = models.CharField(max_length=16, default='')
    index = models.IntegerField(default=0)

我想在数据库中实现这个序列:

...
2020, 134
2020, 135
2021, 1
2021, 2
...

首先我尝试添加

    class Meta:
        unique_together = [['prefix', 'index']]

因此,我将确保在列中始终获得唯一的行值。 问题在于,对于 PostgreSQL,这会创建以下序列:

...
2020, 134
2020, 135
2021, 136
2021, 137
...

任何解决方案如何在 Django 中解决这个问题? 我正在使用 Django 2.2。

-----编辑-----

在 cmets 之后,我手动重置了第一个 2021 实例的索引,并将此代码添加到模型中:

    def save(self, *args, **kwargs):
        # try to save the instance so the index is ordered within prefixes (years)
        # that means- a new year starts new indexing from 1
        saved = False
        self.prefix = str(date.today().year)
        if self.index == 0:
            while not saved:
                try:
                    obj = self.__class__.objects.filter(prefix=self.prefix).last()
                    if obj is None:
                        self.index = 1
                    else:
                        self.index = obj.index + 1
                    super().save(*args, **kwargs)
                    saved = True
                except Exception as e:
                    pass
        if not saved:
            super().save(*args, **kwargs)  # save anyway

这令人惊讶地创建了一个序列

...
2020, 134
2020, 135
2021, 1
2021, 4
2021, 7
...

【问题讨论】:

  • 这里没有技巧,你需要重写 save() 方法并检查索引的最大值为你的“年”值并加 1...
  • 嗨@BriseBalloches,如果我这样做,unique_together 会发生什么:1. 它采用最新的索引,即他自己的索引 2. 递增到 1 3. super().save(. ..) 也再次递增最后,我得到索引 N、N + 3、N + 6 ... 如果我删除 unique_together,我放弃检查唯一性的可能性,其中竞争条件(两个在同一时间创建的对象的独立实例)可能导致具有相同的前缀/索引值。
  • 1.自己的指数怎么样?这是之前创建的实例索引。检查是否 None 然后默认为 0。 2. 增量,到目前为止,它是 (index + 1)。 3. super().save() 如何增加索引?我不认为它是您模型中的任何增量,它是一个简单的 IntegerField。
  • @BriseBalloches 我在帖子中描述了这一点。
  • 抱歉,我不明白为什么每次都加 3。如果可以的话,您应该使用调试器来跟踪索引更改,因为 super.save 添加 1 以及获取最后创建的实例索引是没有意义的。

标签: python django database postgresql


【解决方案1】:

这是我会尝试的:

def save(self, *args, **kwargs):
    # try to save the instance so the index is ordered within prefixes (years)
    # that means- a new year starts new indexing from 1
    self.prefix = str(date.today().year)
    if self.index == 0:
        latest_index = Invoice.objects.filter(prefix=self.prefix).latest('index')
        self.index = latest_index.index + 1 if latest_index else 1
    super().save(*args, **kwargs)

【讨论】:

    猜你喜欢
    • 2017-02-20
    • 2011-04-06
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 1970-01-01
    • 2015-02-26
    • 1970-01-01
    相关资源
    最近更新 更多