我正在创建一个在它的模型中使用一些继承的Django应用程序,主要是因为我需要为UUID和引用分配所有内容,所以我知道它是什么类。这是基类的简化版本:
class BaseElement(models.Model):
uuid = models.CharField(max_length=64, editable=False, blank=True, default=lambda:unicode(uuid4()))
objmodule = models.CharField(max_length=255, editable=False, blank=False)
objclass = models.CharField(max_length=255, editable=False, blank=False)
class ChildElement(BaseElement):
somefield = models.CharField(max_length=255)
我想确保自动设置objmodule,objclass和uuid。我从this post得知,通过编写自己的构造函数来做这件事是个坏主意,而且我最好写一个工厂函数。所以现在我的BaseElement和ChildElement看起来像这样:
class BaseElement(models.Model):
uuid = models.CharField(max_length=64, editable=False, blank=True, default=lambda:unicode(uuid4()))
objmodule = models.CharField(max_length=255, editable=False, blank=False)
objclass = models.CharField(max_length=255, editable=False, blank=False)
def set_defaults(self):
self.objmodule = unicode(self.__class__.__module__)
self.objclass = unicode(self.__class__.__name__)
self.uuid = unicode(uuid4())
class ChildElement(BaseElement):
somefield = models.CharField(max_length=255)
@staticmethod
def create(*args, **kwargs):
ce = ChildElement(*args, **kwargs)
ce.set_defaults()
return ce
这很有效。我可以致电ChildElement.create(somefield="foo")
,我会得到一个合适的对象,uuid
,objmodule
和objclass
字段设置正确。但是,当我浏览并创建更多类ChildElement2
和ChildElement3
时,我发现我正在插入完全相同的静态工厂函数。这对我很感激,因为代码重复很糟糕。
使用普通方法我只需在create
中插入BaseElement
工厂函数,但是,我不能在这里做,因为我没有自己的句柄(因为它没有'已创建)以获取有关调用该方法的对象的类的信息。
我是否有办法将此工厂迁移到BaseElement
类,因此我无需在任何地方复制此代码并仍然拥有它,因此它会自动设置uuid
的值,{ {1}}和objmodule
?
答案 0 :(得分:7)
如果您使create()
成为@classmethod
而不是@staticmethod
,您将可以访问类对象,您可以使用该对象而不是按名称引用它:
@classmethod
def create(cls, *args, **kwargs):
obj = cls(*args, **kwargs)
obj.set_defaults()
return obj
现在这是通用的,可以在基类而不是每个子类上进行。
答案 1 :(得分:2)
我认为你可能更好地覆盖你的BaseElement中的保存。然后在保存时,您可以设置这些字段。这有点像:
class MyBase(models.Model):
uuid = models.CharField(max_length=64, editable=False, blank=True,
default=lambda:unicode(uuid4()))
objmodule = models.CharField(max_length=255, editable=False, blank=False)
objclass = models.CharField(max_length=255, editable=False, blank=False)
def save(self):
if not self.id:
self.objmodule = unicode(self.__class__.__module__)
self.objclass = unicode(self.__class__.__name__)
self.uuid = unicode(uuid4())
super(self.__class__.__base__, self).save()
class InheritedFromBase(MyBase):
new_field = models.CharField(max_length=100)
我测试了它,它似乎做你想要的。我能够创建一个“InheritedFromBase”对象,该对象具有您需要的字段,而不需要大量的代码重复。