如何将可调用函数设置为 AutoField 默认属性?

Posted

技术标签:

【中文标题】如何将可调用函数设置为 AutoField 默认属性?【英文标题】:How to set a callable function to AutoField default attribute? 【发布时间】:2019-06-28 10:22:37 【问题描述】:

我正在尝试覆盖模型的 pk 以使用随机生成器。

这是模型字段:

pk = models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', default=genkey)

和密钥生成器:

def genkey():
    return random.randrange(1,142857)

所以,我想让自动字段尽可能多地执行genkey 函数,直到它得到一个未使用的密钥。是否有我没有找到的属性,或者我需要在生成器中对其进行编码(通过获取所有使用的键)?

我的主要目标是使生成器尽可能通用,而不是为每个模型定义自定义生成器。

【问题讨论】:

AutoField 的想法是 数据库 将自动创建一个 id。 我知道,它可以是IntegerField 或其他,我在这里使用AutoField,因为它是默认的pk 字段类型。 【参考方案1】:

如文档所述,AutoField [Django-doc] 是:

IntegerField 根据可用 ID 自动递增。您通常不需要直接使用它;如果您没有另外指定,主键字段将自动添加到您的模型中。

因此它是一个IntegerField [Django-doc],因此我们可以简单地使用IntegerField,就像这样:

class SomeModel(models.Model):
    pk = models.IntegerField(editable=False, auto_created=True, primary_key=True, verbose_name='ID', default=genkey)
    # ...

因此在AutoField 上指定默认值与AutoField 所做的有点矛盾。如果您使用editable=False [Django-doc] 创建IntegerField,以确保至少在默认情况下,它不会包含在ModelForm 中。这实质上就是主键的作用。

【讨论】:

为什么一定要blank=True?默认设置为实例化,因此该字段永远不会为空。 @DanielRoseman:您不需要将其设置为 blank=True,但 AutoField 将其设置为空白 (github.com/django/django/blob/master/django/db/models/fields/…)。可能是因为否则它将出现在 ModelForm 中,而 pk 通常不是用户应该创建/更新的东西。 不,那是因为你说 AutoField 没有默认值,它是由数据库在保存时设置的,所以如果空白为 False,那么模型将永远无效。这不是这里的情况,我们确实有一个默认值。 @DanielRoseman:嗯……是的。也许editable=False 更好?【参考方案2】:

经过一些研究和测试,我最终创建了一个类。

class RandomIDKey(models.Model):
    id = models.IntegerField(
        auto_created=True,
        primary_key=True,
        serialize=False,
        verbose_name='ID',
        unique=True,
        db_index=True,
        editable=False
    )

    def save(self, *args, **kwargs):
        if not self.id:
            self.id = genkey(type(self))
        super().save(*args, **kwargs)

    class Meta:
        abstract = True

具有公共功能:

def genkey(model):
    generated_key = random.randrange(1, 2147483648)
    if model.objects.filter(pk=generated_key).exists():
        generated_key = genkey(model)
    return generated_key

使用 AutoField 是个坏主意,因为该字段不是由数据库自动生成的,因此使用 IntegerField

【讨论】:

以上是关于如何将可调用函数设置为 AutoField 默认属性?的主要内容,如果未能解决你的问题,请参考以下文章

Python Cookbook(第3版)中文版:15.12 将函数指针转换为可调用对象

Django 模型字段可调用默认值不起作用

我可以将 simulink 中的 matlab 函数中的参数设置为可调吗?

可调用函数支持缓存吗?

[C++11]可调用对象绑定器

JavaScript中可调用对象的构造函数[duplicate]