如何将可调用函数设置为 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 将函数指针转换为可调用对象