2009-12-11 15 views
5

私は、すべてのUUIDと参照を割り当てる必要があるため、モデルの継承を使用するDjangoアプリケーションを作成しています。私はobjmodule、objclass、およびUUIDが自動的に設定されていることを確認したいと思いますPythonとDjangoの継承とファクトリ関数

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) 

:ここでは、基本クラスの簡易版です。私は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,objmoduleobjclassのフィールドが正しく設定された適切なオブジェクトが得られます。しかし、ChildElement2ChildElement3のようなクラスを作成すると、まったく同じ静的ファクトリ関数が挿入されています。コードの重複が悪いので、これは私を怒らせます。

通常の方法ではBaseElementcreateファクトリ関数を挿入していますが、私は(まだ作成されていないため)ハンドルを持たないためここにはできませんメソッドを呼び出したオブジェクトのクラスに関する情報。

は、私はどこにでもこのコードを複製する必要はありませんし、まだそれはそれは自動的に uuidobjmodule、および objclassの値を設定しますので、持っているので、私は BaseElementクラスにこの工場を移行することができます方法はありますか?

答えて

7

あなたはcreate()@classmethodの代わり@staticmethodを作る場合、あなたはあなたが名前によってそれを参照するのではなく、使用することができ、クラスオブジェクトへのアクセスがあります:

@classmethod 
def create(cls, *args, **kwargs): 
    obj = cls(*args, **kwargs) 
    obj.set_defaults() 
    return obj 

をこれが今ジェネリックで、行くことができますそれぞれの子クラスの代わりに基本クラスに追加します。

+1

これはまさに私が探していたものです。 '@ classmethod'について私に思い出させてくれてありがとう。私が頻繁に使うものではありません。 – Pridkett

+0

Pythonでは、 '@ staticmethod'にはまれなケースがあります。これは、あまり頻繁に使用しない方がいいでしょう。しばしば何かが '@ classmethod'でなければモジュールで単純なトップレベル関数として適切です。 –

2

代わりにBaseElementのsaveをオーバーライドした方が良いかもしれないと思います。保存したら、これらのフィールドを設定することができます。

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"オブジェクトを作成することができました。コードの重複はほとんどありませんでした。

+0

+1:単に「保存」をオーバーライドすることは、ほとんど常に正しいことです。 –

+1

それは近いですし、受け入れられるかもしれませんが、私が必要とするものではありません。今私はいくつかのオブジェクトをサーバー上に作成し、AJAXyアプリケーションで使用するためにそれらをクライアントにシリアル化します。クライアントは属性を変更してオブジェクトを保存できます。あなたの設定では、 'uuid'、' objmodule'、 'objclass'は保存されるまで割り当てられません。私がクライアント上で 'uuid'を使うと、おそらくサーバーに何らかのロジックを追加するか、クライアントがそれを割り当てるようにする必要があります。近いので、最初に 'save'を呼び出さずに方法を見つけたいと思います。しかし、これが正しい方法であれば対処することができます。 – Pridkett