我发现在将它传递给super().__init__
之前,您不会从kwargs
中删除参数skip
。这意味着“跳过”是一个字段的名称,否则你得到异常TypeError("'skip' is an invalid keyword argument for this function")
。
如果你确实需要do_something()
,那么在使用之前必须先创建对象,以免任何人都忘记避免所有不支持的方式(??),然后自定义管理器等是不够的。
你的问题是,models.Model.__init__(...)
支持*args
和**kwargs
参数非常完美,他们应该是可以互换的。你打破了它,如果“跳过”是由位置参数的完整元组传递的,那么你就忽略它。那就是如果该对象是从数据库创建的。阅读文档Customizing model loading:
...如果模型的所有领域都存在,那么值保证在__init__()
预计的顺序。也就是说,该实例可以通过cls(*values)
...
创建。
| @classmethod
| def from_db(cls, db, field_names, values):
| ...
| instance = cls(*values)
| ...
一个简单的方法来解决它是调用do_something()
super().__init__
后,读self.skip
,而不是执行解析都kwargs和args。
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.skip:
do_something()
的一个问题可能是信号“post_init”那是在super().__init__
结束时,如果你需要它发送。
最后一种可能性是支持*args
(哈克,但仍然采用某种方式记录名称):
def __init__(self, *args, **kwargs):
if kwargs:
skip = kwargs.get('skip', False)
else:
# check "val is True" in order to skip if val is DEFERRED
skip = any(field.name == 'skip' and val is True
for val, field in zip(args, self._meta.concrete_fields)
)
if not skip:
do_something()
super().__init__(*args, **kwargs)
编辑:也许你就不需要你想要的东西和Proxy model,可以做一些事情有时通过基本模型对同一数据库表中的相同数据进行额外处理是正确的解决方案。 (“Skip”看起来不像是描述对象数据的名称,而是像描述对象创建模式的名称一样,比内部的神秘开关更容易测试和维护子类。)
'do_something ()'做?可能有更好的方法来覆盖'__init__'。 – Alasdair
您可以编写自己的管理器并将'do_something()'重新放置到新的默认管理器中。 –
@Alasdair,是啊,我相信它会更好,我在[Django文档](https://docs.djangoproject.com/en/1.11/ref/models/instances/)中读到了这一点,它不是重写'__init__'方法的好主意。但在这种情况下,它会将属性添加到模型对象,应该在对象更改之前使用它。 '__init__'方法中的'do_something'位置确保了这一点。 –