9

我有一系列看起来像这样的模型:

class Analysis(models.Model):
    analysis_type = models.CharField(max_length=255)

    def important_method(self):
        ...do stuff...


class SpecialAnalysis(Analysis):
    class Meta:
        proxy = True

    def important_method(self):
        ...something different...

这都是很标准的。但是,我想做的是Analysis根据analysis_type字段的值自动将模型转换为代理模型。例如,我希望能够编写如下所示的代码:

>>> analysis = Analysis.objects.create(analysis_type="nothing_special")
>>> analysis.__class__
<class 'my_app.models.Analysis'>

>>> analysis = Analysis.objects.create(analysis_type="special")
>>> analysis.__class__
<class 'my_app.models.SpecialAnalysis'>

>>> analysis = Analysis.objects.get(pk=2)
>>> analysis.__class__
<class 'my_app.models.SpecialAnalysis'>

>>> # calls the ``important_method`` of the correct model
>>> for analysis in Analysis.objects.all():
...     analysis.important_method()

这甚至有可能吗?此处提出了一个类似的问题,它实际上为迭代示例提供了一些代码,但它仍然给我留下了如何从其父级获取或创建代理类实例的问题。我想我可以重写一堆管理器方法,但我觉得必须有一种更优雅的方法来做到这一点。

4

2 回答 2

11

我还没有找到一种“干净”或“优雅”的方式来做到这一点。当我遇到这个问题时,我通过欺骗 Python 来解决它。

class Check(models.Model):
    check_type = models.CharField(max_length=10, editable=False)
    type = models.CharField(max_length=10, null=True, choices=TYPES)
    method = models.CharField(max_length=25, choices=METHODS)
    'More fields.'

    def __init__(self, *args, **kwargs):
        super(Check, self).__init__(*args, **kwargs)
        if self.check_type:
            map = {'TypeA': Check_A,
                'TypeB': Check_B,
                'TypeC': Check_C}
            self.__class__ = map.get(self.check_type, Check)

    def run(self):
        'Do the normal stuff'
        pass


class Check_A(Check):
    class Meta:
        proxy = True

    def run(self):
        'Do something different'
        pass

class Check_B(Check):
    class Meta:
        proxy = True

    def run(self):
        'Do something different'
        pass


class Check_C(Check):
    class Meta:
        proxy = True

    def run(self):
        'Do something different'
        pass

它不是很干净,但它是最容易找到解决我问题的方法。

也许这对你有帮助,也许没有。

我也希望其他人有一个更 Pythonic 的解决方案来解决这个问题,因为我正在计算直到这个方法失败并回来困扰我的日子。

于 2013-08-27T20:01:55.313 回答
6

这是一个很好的方法,我并不特别认为它是作弊。这是恕我直言,该功能的一些增强__init__功能因此在添加更多类时不必更改。

def __init__(self, *args, **kwargs):
    super(Analysis, self).__init__(*args, **kwargs)
    if not self.__type and type(self) == Analysis:
        raise Exception("We should never create a base Analysis object. Please create a child proxy class instead.")

    for _class in Analysis.__subclasses__():
        if self.check_type == _class.__name__:
            self.__class__ = _class
            break

def save(self, **kwargs):
    self.check_type = self.__class__.__name__
    super(Analysis, self).save(**kwargs)

希望这可以帮助!

于 2014-11-04T16:43:47.220 回答