在 Django 模型类上设置 __new__ 是否安全?
这个问题不同于: 在类上使用 __new__从 Django 模型派生的代码不起作用
这个问题询问如何使 __new__
工作。
这个问题问:将 __new__ 与 Django 模型一起使用有哪些陷阱?
特别是,我有以下代码,它的存在是为了在类上安装一个类方法,它需要知道它源自哪个类(即它需要告诉它是否在子类上调用)。 这会以意想不到的方式爆炸吗?
class Director(models.Model, Specializable, DateFormatter, AdminURL, Supercedable): # my own mixin classes
# all other properties etc snipped
@staticmethod # necessary with django models
def __new__(cls, *args, **kwargs):
Specializable.create_subclass_translator(cls, install = 'create_from_officer')
return models.Model.__new__(cls, *args, **kwargs)
为了完整起见,create_subclass_translator
做了这样的事情:
@classmethod
def create_subclass_translator(clazz, Baseclass, install=None):
def create_from_other_instance(selfclass, old_instance, properties):
if selfclass is Baseclass: raise TypeError("This method cannot be used on the base class")
# snipped for concision
return selfclass(**properties)
new_method = classmethod(create_from_other_instance)
if install and not hasattr(Baseclass, install):
setattr(Baseclass, install, new_method)
return new_method
对于那些想知道这要完成什么的人,类方法create_from_other_instance
是一个工厂,它通过复制基类属性并正确设置 ancestor_link
属性来模拟从一个子类更改为另一个子类的模型子类实例。
This question is different from: Using __new__ on classes derived from Django's models does not work
That question asks how one can make __new__
work.
This question asks: What are the pitfalls of using __new__
with Django models?
In particular, I have the following code, which exists to install a classmethod on the class, which needs to know which class it originates in (i.e. it needs to tell whether it is being called on a subclass or not). Will this blow up in unexpected ways?
class Director(models.Model, Specializable, DateFormatter, AdminURL, Supercedable): # my own mixin classes
# all other properties etc snipped
@staticmethod # necessary with django models
def __new__(cls, *args, **kwargs):
Specializable.create_subclass_translator(cls, install = 'create_from_officer')
return models.Model.__new__(cls, *args, **kwargs)
For completeness, create_subclass_translator
does something like this:
@classmethod
def create_subclass_translator(clazz, Baseclass, install=None):
def create_from_other_instance(selfclass, old_instance, properties):
if selfclass is Baseclass: raise TypeError("This method cannot be used on the base class")
# snipped for concision
return selfclass(**properties)
new_method = classmethod(create_from_other_instance)
if install and not hasattr(Baseclass, install):
setattr(Baseclass, install, new_method)
return new_method
For those who wonder what this is accomplishing, the classmethod create_from_other_instance
is a factory which simulates a model subclass instance changing from one subclass to another, by copying over the baseclass properties, and setting the ancestor_link
property correctly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于您正确地调用了基类
__new__
,我不希望出现意外 - 它应该正常工作 - 如果做错了,实例化时会立即失败。那里不应该有任何微妙的错误 - 只需编写一些实例化此类的单元测试即可。如果它变得“错误”,测试就会失败。
Since you are properly calling the base class
__new__
, I would not expect surprises there - it should just work - and if done wrong, fail at once at instantiation.You should not have any subtle errors there - just write some unit tests that instantiate this class. If it ever become "wrong" the tests will fail.