Python和Django中的继承和工厂函数

时间:2009-12-11 21:32:36

标签: python django inheritance

我正在创建一个在它的模型中使用一些继承的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"),我会得到一个合适的对象,uuidobjmoduleobjclass字段设置正确。但是,当我浏览并创建更多类ChildElement2ChildElement3时,我发现我正在插入完全相同的静态工厂函数。这对我很感激,因为代码重复很糟糕。

使用普通方法我只需在create中插入BaseElement工厂函数,但是,我不能在这里做,因为我没有自己的句柄(因为它没有'已创建)以获取有关调用该方法的对象的类的信息。

我是否有办法将此工厂迁移到BaseElement类,因此我无需在任何地方复制此代码并仍然拥有它,因此它会自动设置uuid的值,{ {1}}和objmodule

2 个答案:

答案 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”对象,该对象具有您需要的字段,而不需要大量的代码重复。