如何在 Django 中每年重置自动增量数

How to reset auto increment number every year in Django

我有一个带有自动递增字段 ID 的模型 IncomingCorrespondence。我也有字段 number,我想为这个字段做两件事:

  1. 这个字段会自动增加它的值,就像ID
  2. 每个新年它的值将从 0(或 1)重新开始
ID Number Date
285 285 2020-03-12
286 286 2020-04-19
287 1 2021-01-01
class IncomingCorrespondence(models.Model):
   ID = models.models.AutoField(primary_key=True)
   date = models.DateField(null=True)
   number = models.IntegerField(null=True)

我怎样才能以最有效和可靠的方式做到这一点?

你不需要存储这个数字,你可以简单地通过自从那一年开始以来存储在数据库中的项目数来导出它:

class IncomingCorrespondence(models.Model):
    date = models.DateField(null=True)
    created = models.DateTimeField(auto_now_add=True)

    @property
    def number(self):
        return IncomingCorrespondence._base_manager.filter(
            <strong>created__year=self.created.year</strong>,
            <strong>created__lt=self.created</strong>
        ).count() + 1

因此,我们有一个时间戳 created,它将存储对象创建的日期时间,我们计算时间戳前那一年的 IncomingCorrespondence 数加一。在这种情况下,您可以使用像 django-softdelete [GitHub] 这样的包来将已删除的对象保留在数据库中,并在查看项目时将其过滤掉。

另一种方法可能是将最大值加一分配给字段:

from django.db.models import Max
from django.utils.timezone import now

def next_number():
    data = IncomingCorrespondence._base_manager.filter(
        date__year=now().year
    ).aggregate(
        max_number=Max('number')
    )['max_number'] or 0
    return data + 1

class IncomingCorrespondence(models.Model):
   ID = models.models.AutoField(primary_key=True)
   date = models.DateField(auto_now_add=True)
   number = models.IntegerField(<strong>default=next_number</strong>, editable=False)

但是这里 Django 会通过查询来发送数字。如果有多个线程同时创建一个 IncomingCorrespondence,那么这可能会失败。也取决于插入的时间,而不是IncomingCorrespondence对象的date

您应该使用一些方法来计算 number,例如查询今年创建 IncomingCorrespondence 的计数。它不应该以任何其他方式完成(例如 cronjob),因为它不稳定(crontab 可能会失败并且您最终会出现异常(甚至无法注意到),或者您将正确创建实例在 crontab 重置序列之前)