2016-07-01 3 views
6

私はモデルフィールド用の汎用mixin(フォームフィールドとは対照的に)を作成しようとしていますが、mixinのinitは名前付き引数をとります。私は別のクラスでミックスインをインスタンス化するのに苦労している。 3回を実行しているのinitされている理由Djangoモデルフィールドの作成方法mixin

<class 'myapp.mixintest.fields.MyMixinCharField'> myarg 
<class 'myapp.mixintest.fields.MyMixinCharField'> None 
<class 'myapp.mixintest.fields.MyMixinCharField'> None 
Migrations for 'mixintest': 
    0001_initial.py: 
     - Create model MyMixinModelTest 

まず、:ここで

はコード

class MyMixin(object): 
    def __init__(self, new_arg=None, *args, **kwargs): 
     super(MyMixin, self).__init__(*args, **kwargs) 
     print self.__class__, new_arg 


class MyMixinCharField(MyMixin, models.CharField): 
    pass 

... 

class MyMixinModelTest(models.Model): 
    myfield = MyMixinCharField(max_length=512,new_arg="myarg") 

このモデルの移行を作るには、次の出力が生成されますか? 2番目の2つのkwarg 'new_arg'はどこですか? django用のフィールドミックスインを作成するにはどうすればよいですか?

EDIT: another questionとは対照的に、この質問を約フィールドミックスインを尋ねる、リンクされた質問はモデルミックスインを指します。

+0

どのバージョンのdjangoを使用していますか? – Aya

+0

私はバージョン1.9を使用しています – jmerkow

+0

@solarissmokeそれは同じ質問ではありません。 –

答えて

2

まず、なぜ3回を実行しているinitのですか?

models.pyは一度しか輸入されているが、このよう

myfield = MyMixinCharField(max_length=512, new_arg="myarg") 

...として、その中に作成されたFieldオブジェクトは、...キーワード引数を使用してフィールドコンストラクタを呼び出すことを伴う数回、クローン化されています彼らはもともとで作成されました。あなたは

File "django/db/migrations/state.py", line 393, in from_model 
    fields.append((name, field.clone())) 
    File "django/db/models/fields/__init__.py", line 464, in clone 
    return self.__class__(*args, **kwargs) 
    File "myproj/myapp/models.py", line 11, in __init__ 
    traceback.print_stack() 

がどこにある...それが起こっている場所を確認するために、出力に次の数回を示し

import traceback 

class MyMixin(object): 
    def __init__(self, new_arg=None, *args, **kwargs): 
     super(MyMixin, self).__init__(*args, **kwargs) 
     print self.__class__, new_arg 
     traceback.print_stack() 

を... ... tracebackモジュールを使用することができます2番目の2つのkwarg 'new_arg'?

あなたはもともと呼ば

...

myfield = MyMixinCharField(max_length=512, new_arg="myarg") 

... "myarg"からnew_argパラメータとして渡さ...

def __init__(self, new_arg=None, *args, **kwargs): 

...しかし、あなたのでされているドンそのパラメータを基になるFieldコンストラクタに渡します。

super(MyMixin, self).__init__(*args, **kwargs) 

...基礎となるFieldオブジェクトのどこにも格納されていないため、フィールドが複製されるとき、new_argパラメータはコンストラクタに渡されません。

しかし、スーパークラスのコンストラクタにそのオプションを渡すと...


どう

File "myproj/myapp/models.py", line 29, in MyMixinModelTest 
    myfield = MyMixinCharField(max_length=512, new_arg="myarg") 
    File "myproj/myapp/models.py", line 25, in __init__ 
    super(MyMixinCharField, self).__init__(*args, **kwargs) 
    File "django/db/models/fields/__init__.py", line 1072, in __init__ 
    super(CharField, self).__init__(*args, **kwargs) 
TypeError: __init__() got an unexpected keyword argument 'new_arg' 
CharFieldは、そのキーワードの引数をサポートしていないため、動作しませんので、あなたが買ってあげます私はdjango用のフィールドmixinを作成するのですか?

カスタムフィールドオプションを追加したい場合は、このクローニング動作のため、あなたは、Djangoはあなたの新しいオプションをシリアル化できるように、カスタムdeconstruct()メソッドを定義する必要があるので...

class MyMixin(object): 
    def __init__(self, new_arg=None, *args, **kwargs): 
     super(MyMixin, self).__init__(*args, **kwargs) 
     self.new_arg = new_arg 
     print self.__class__, new_arg 

    def deconstruct(self): 
     name, path, args, kwargs = super(MyMixin, self).deconstruct() 
     kwargs['new_arg'] = self.new_arg 
     return name, path, args, kwargs 


class MyMixinCharField(MyMixin, models.CharField): 
    pass 


class MyMixinModelTest(models.Model): 
    myfield = MyMixinCharField(max_length=512, new_arg="myarg") 

...どの出力...

<class 'myapp.models.MyMixinCharField'> myarg 
<class 'myapp.models.MyMixinCharField'> myarg 
<class 'myapp.models.MyMixinCharField'> myarg 
+0

私は私の答えのすべての質問に答えなかった、あなたはした。だから私はあなたのことを受け入れるだろう。 – jmerkow

+0

簡単な質問、私の答えでは、私はMyMixinをモデルから継承しています。フィールド、これは何かに影響しますか? – jmerkow

+0

@jmerkow「Model」でメタクラスを使用しているため、明確に答えられることは特に簡単な質問ではありません。 'MyMixin'が' Field'を直接サブクラス化している場合、 'Field'で定義された関数を上書きする' CharField'の関数は無視されることがあります。おそらくその可能性を避け、おそらくmixinがやるべきことである 'MyMixin'サブクラス' object'を持つほうが安全でしょう。 – Aya

1

だから、たくさんの微妙な調整や再読み込みの後で分かりました。django docs on custom model fields initと一緒にデコンストラクタが必要です。 Djangoフィールドは、deconstructメソッドをシリアル化する必要があります。

ミックスインは、同様に、この方法を持っている必要があります。

class MyMixin(object): 
def __init__(self, new_arg=None, *args, **kwargs): 
    self.new_arg = new_arg 
    super(MyMixin, self).__init__(*args, **kwargs) 

def deconstruct(self): 
    name, path, args, kwargs = super(MyMixin, self).deconstruct() 
    if self.new_arg is not None: 
     kwargs['new_arg'] = self.new_arg 
    return name, path, args, kwargs 
+0

あなたはこれを投稿したときに、より詳細な回答を書いていました。 :) – Aya

関連する問題