为啥我不能使用模型方法作为默认值?无论如何,Python/Django 模型中的 self 是啥?

Posted

技术标签:

【中文标题】为啥我不能使用模型方法作为默认值?无论如何,Python/Django 模型中的 self 是啥?【英文标题】:Why can't I use model methods as defaults? What is self in Python/Django models anyway?为什么我不能使用模型方法作为默认值?无论如何,Python/Django 模型中的 self 是什么? 【发布时间】:2015-12-11 08:21:32 【问题描述】:

我在理解self 的行为方面有一个非常基本的问题。

具体来说,我不明白为什么以下两个sn-ps代码都不起作用,第一个导致解释器抱怨

self 缺少参数,

第二个

self 无法被引用。

class Model(models.Model)
    name = models.CharField(max_length=200)
    auto_gen_field = models.CharField(max_length=200, default=gen_field())

    def gen_field(self):
        return self.name + 'something'

class Model(models.Model)
    name = models.CharField(max_length=200)
    auto_gen_field = models.CharField(max_length=200, default=gen_field(self))

    def gen_field(self):
        return self.name + 'something'

以下代码也使用了self,可以正常工作:

class Model(models.Model)
    name = models.CHarField(max_length=200)
    auto_gen_field = models.CharField(max_length=200, blank=True)

    def gen_field(self):
        return self.name + 'something'

    def save(self):
        self.auto_gen_field = self.gen_field()
        super(Model, self).save(*args, **kwargs)

为什么self 引用存在于一处而不存在于另一处?

如何修复前两个 sn-ps?

【问题讨论】:

【参考方案1】:

您在声明该字段时调用该方法。那时没有self

无论如何,您都不想这样做。除了 self 的任何问题之外,这样做会为默认值返回一个静态值,因此所有实例都将使用相同的值。这就是传递 callable 很重要的原因:gen_field - 而不是结果 - gen_field()

(但请注意,这仍然不起作用:实例不会被传递给函数,因为它没有作为实例上的方法被调用。覆盖保存是要走的路。)

【讨论】:

【参考方案2】:

self按照惯例(它实际上是一个和其他任何名称一样的名称,重要的是它是您的类方法的 第一个参数)一个 引用类的当前实例,或多或少类似于 C++/Java 中的 this

现在,在

class Model(models.Model)
    name = models.CharField(max_length=200)
    auto_gen_field = models.CharField(max_length=200, default=gen_field())

当评估models.CharField(max_length=200, default=gen_field()) 时,没有该类的实例,因此您不能在其中添加self。 它没有也不可能有意义。

现在,来自:https://docs.djangoproject.com/en/1.8/ref/models/fields/#django.db.models.Field.default

Field.default¶

字段的默认值。这可以是一个值或可调用的 目的。如果可调用,它将在每次有新对象时被调用 已创建。

默认不能是可变对象(模型实例、列表、集合、 等),作为对该对象的同一实例的引用将是 在所有新模型实例中用作默认值。相反,包装 可调用对象中所需的默认值。

你想传递一个callable - 这基本上类似于function pointer。

起作用的是:

def some_function():
     return something

...

auto_gen_field = models.CharField(max_length=200, default=some_function)

但是,您可以gen_field() 之类的模型方法用作default,因为Django 确实将模型实例作为提供的第一个参数传递可调用。

你必须覆盖save

【讨论】:

以上是关于为啥我不能使用模型方法作为默认值?无论如何,Python/Django 模型中的 self 是啥?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当我使用 JSON.NET 反序列化时会忽略我的默认值?

HSQLDB - 为啥我不能将默认值设置为 -1

PHP 使用 $this->variable 作为类方法参数默认值

为啥 Django 将 postgres JSONField 值作为字符串返回?

为啥不能使用符号而不是字符串来访问 Rails 模型属性?

为啥在注释中禁止 null 作为默认值?