自动增量字段取决于 django 中特定值出现的数量

Posted

技术标签:

【中文标题】自动增量字段取决于 django 中特定值出现的数量【英文标题】:Autoincrement field dependent for number of specific value appearances in django 【发布时间】:2022-01-19 17:05:14 【问题描述】:

我正在寻找一个很好的例子或建议来解决我在 Django 和 python 中的问题。我有像 Customer 这样的简单模型

class Customer(models.Model):
    customer_name = models.CharField(max_length=500)
    CUSTOMER_CHOICES = [
        ('pc', 'Private Customer'),
        ('bc', 'Business Customer'),
    ]
    customer_type = models.CharField(max_length=2, choices=CUSTOMER_CHOICES)
    customer_number = models.IntegerField(blank=True)

对于所有客户,我想根据客户类型和十进制数字构建(并在页面上显示)特定的“客户编号”。我想我可能会将这个值存储在 Customer 表中(有点像这样):

|id|customer_name|customer_type|customer_number|
|1 |Private 1    |pc           |1              |
|2 |Private 2    |pc           |2              |
|3 |Business 1   |bc           |1              |
|4 |Private 3    |pc           |3              |
|5 |Business 2   |bc           |2              |    

当然,当我要修改客户名称或其他值(客户类型和客户编号除外)时,我不想更新此编号。

我认为下面的代码不起作用(这只是最初想到的一个示例),因为我不知道当我将有两个不同的会话以及按下保存按钮时代码将如何工作同时。我不知道这段代码会正确处理一个新对象,当我们之前删除时,例如第二行接下来我们要添加“新私人客户”。

编辑代码:

    def save(self, *args, **kwargs):
        # Get last object by customer type
        last_obj = Customer.objects.all().filter(customer_type=self.customer_type).last()

        # Checking if we had any entries by customer type
        # if not, this element must be first on the list
        # next, if new val is None we need to add 1 to the counter
        print(last_obj.customer_number)
        if last_obj is None:
            self.customer_number = 1
        else:
            if self.customer_number is None:
                self.customer_number = last_obj.customer_number + 1

        super(Customer, self).save(*args, **kwargs)

Django 有什么工具可以很好地做到这一点吗?

【问题讨论】:

“避免数字间隔或重复数字”是什么意思? 也许避免差距太大,但我需要有一致的数据。当我删除 Private2 时,我会有间隙但没关系,但是当我想保存像 Private4 这样的新对象时,这个对象的“customer_number”应该有 4。避免重复数字是当我想要保存两个像 Private4 这样的对象时和 Provate5,当我同时单击保存时,我担心这些对象将获得相同的客户编号,因为这两个对象从保存方法中变量 last_number 的查询中获得相同的值。 【参考方案1】:

Django 没有单一的特定工具来实现您的结果。这里有两个选项。

1.保存()方法 这基本上是你的方法。但它应该与 Django 的 UniqueConstraint.condition (docs) 方法结合使用,以确保 customer_number 字段对于每个客户类型都是唯一的。模型约束可以设置为meta option。

class Customer(models.Model):
    customer_name = models.CharField(max_length=500)
    CUSTOMER_CHOICES = [
        ('pc', 'Private Customer'),
        ('bc', 'Business Customer'),
    ]
    customer_type = models.CharField(max_length=2, choices=CUSTOMER_CHOICES)

    class Meta:
        constraints = [
            models.UniqueConstrained(fields=['customer_number'], condition=Q(customer_type='pc'), name='unique_pc_customer'),
            models.UniqueConstrained(fields=['customer_number'], condition=Q(customer_type='bc'), name='unique_bc_customer'),
            ]

如果违反了约束,则会引发IntegrityError。您可以在模型save() 方法中处理错误。

def save():
    try:
       #Set your customer_number
    except IntegrityError:
       #Handle the error as you wish

2。单独的模型 您可以定义两个附加模型,一个用于 pc,一个用于 bc。然后,这些模型将与您的 Customer 模型一对一地关联。您的 pc 模型实例和 bc 模型实例的 id 将是您的客户编号。

【讨论】:

感谢@yagus 的回复!我知道我必须在 save 方法中做所有事情,但我真的很害怕奇怪的情况。我编辑了保存方法,它可以工作,但我不知道这段代码能不能正常工作。我不怕诚信,因为我会将客户类型存储在另一张桌子上。我知道我可以分离模型,但是其他方法可能不清楚或者我将代码量增加一倍 @ashby,如果您将约束添加到模型中并按照答案中的说明处理保存方法中的完整性错误,它将正确完成工作。

以上是关于自动增量字段取决于 django 中特定值出现的数量的主要内容,如果未能解决你的问题,请参考以下文章

Django QuerySet:用于计数值出现的附加字段

自动生成的 prisma 增量字段

Django Rest Framework:POST时自动填充模型的字段?

MYSQL 自动增量按字段分类

如果在下拉列表中选择了特定值,则 Django 管理员显示/隐藏字段

Django Admin显示/隐藏字段如果在下拉菜单中选择了特定值