Django模型中IntegerField的顺序编号

时间:2019-02-06 08:42:54

标签: django django-models

我有一个看起来差不多的模型:

class MyModel(models.Model):
    period = models.IntegerField(unique=True)
    beta = models.IntegerField()
    gamma = models.FloatField()

我需要period是从1到N的数字,其中N是此模型中的记录数。因此,如果有5条记录,它将有一组整数[1、2、3、4、5],但是如果有人删除了数字4,则应以使数字5变为4的方式进行更新,因此它们将再次连续。

正确的方法是什么?

1 个答案:

答案 0 :(得分:1)

重写.delete()和.save()方法以相对于整个查询集使用索引位置更新周期号。周期值可能与实例的实际主键不匹配,但是它将代表基数位置。

class MyModelManager(models.Manager):
    def update_periods(self):
        for instance in self.all():
            instance.period = instance.get_index()
            instance.save()


class MyModel(models.Model):
    period = models.IntegerField(unique=True)
    beta = models.IntegerField()
    gamma = models.FloatField()

    objects = MyModelManager()

    class Meta:
        ordering = ('pk',)

    def get_index(self):
        # Return the index position of this instance with regards to the sorted queryset
        return list(MyModel.objects.values_list('pk', flat=True)).index(self.pk) + 1

    def delete(self, *args, **kwargs):
        super(MyModel, self).delete(*args, **kwargs)
        MyModel.objects.update_periods()

    def save(self, *args, **kwargs):
        if not self.pk:
            # Only update new instances
            super(MyModel, self).save(*args, **kwargs)
            MyModel.objects.update_periods()
        else:
            super(MyModel, self).save(*args, **kwargs)

您还可以使用信号处理程序来避免覆盖模型方法。这是概念的证明。用这种方式更新所有期间效率不高,需要使用查询集注释或数据库功能(https://docs.djangoproject.com/en/2.1/ref/models/database-functions/)更新为批量更新。