2013-08-27 12 views
5

私はこのように見える一連のモデルを持っている:彼らの基本クラスからDjangoのプロキシモデルのインスタンスを作成

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_typeフィールドの値に基づいて、Analysisモデルを自動的にプロキシモデルに変換することです。たとえば、次のようなコードを書くことができます:

>>> 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() 

これはリモートでも可能ですか?同様の質問が繰り返しの例のコードを実際に与えるhereと尋ねられましたが、それでも親からプロキシクラスのインスタンスを取得または作成する方法の問題が残っています。私はちょうどマネージャメソッドの束を無効にすることができると思うが、私はそれを行うよりエレガントな方法が必要であるように感じる。

答えて

8

これを行うための「クリーン」または「エレガントな」方法は見つかりませんでした。私がこの問題に遭遇したとき、私は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 

それは本当にきれいではないのですが、私の問題を解決している見つけるための最も簡単なハックでした。

これはおそらくあなたに役立つかもしれません。

私はまた、これは素晴らしいアプローチと私ドン..ですこのメソッドは失敗し、私を悩ませ戻って来るまで、私は日数えていますので、他の誰かがこの問題へのより多くの神託のソリューションを持っている

+1

これは間違いなく、私が試していたクレイジーなものよりもきれいです。ご協力いただきありがとうございます! –

+0

あなたの方法は失敗することはまずありませんが、手動マッピングは正確に拡張できません。将来の訪問者は、Model .__サブクラス__()メソッドを使用してプロキシモデルのリストを取得し、必要に応じてそれらの一部またはすべてを動的にクエリする方がよいでしょう。 – Ivan

4

を望んでいます特にそれをチートと見なす。ここではIMHOの__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) 

希望します。

+0

おっと。 '__subclasses__'について知りませんでしたが、メンテナンス性が確実に向上します。 – EWit

関連する問題