既存のモデルをサブクラス化しています。親クラスのメンバーの多くを、代わりに子クラスのメンバーにしたいと思います。
たとえば、私はモデルSwallowを持っています。今、EuropeanSwallow(Swallow)とAfricanSwallow(Swallow)を作っています。すべてではありませんが、いくつかのSwallowオブジェクトを使用して、移動可能かどうかに応じて、EuropeanSwallowまたはAfricanSwallowのいずれかにします。
どうすれば移動できますか?
既存のモデルをサブクラス化しています。親クラスのメンバーの多くを、代わりに子クラスのメンバーにしたいと思います。
たとえば、私はモデルSwallowを持っています。今、EuropeanSwallow(Swallow)とAfricanSwallow(Swallow)を作っています。すべてではありませんが、いくつかのSwallowオブジェクトを使用して、移動可能かどうかに応じて、EuropeanSwallowまたはAfricanSwallowのいずれかにします。
どうすれば移動できますか?
ちょっとしたハックですが、これは機能します:
swallow = Swallow.objects.get(id=1)
swallow.__class__ = AfricanSwallow
# set any required AfricanSwallow fields here
swallow.save()
私はこれがずっと後であることを知っています、しかし私は同じようなことをする必要があり、そして多くを見つけることができませんでした。私はここでいくつかのソースコードに答えが埋もれているのを見つけましたが、十分なクラスメソッドの例も書きました。
class AfricanSwallow(Swallow):
@classmethod
def save_child_from_parent(cls, swallow, new_attrs):
"""
Inputs:
- swallow: instance of Swallow we want to create into AfricanSwallow
- new_attrs: dictionary of new attributes for AfricanSwallow
Adapted from:
https://github.com/lsaffre/lino/blob/master/lino/utils/mti.py
"""
parent_link_field = AfricanSwallow._meta.parents.get(swallow.__class__, None)
new_attrs[parent_link_field.name] = swallow
for field in swallow._meta.fields:
new_attrs[field.name] = getattr(swallow, field.name)
s = AfricanSwallow(**new_attrs)
s.save()
return s
ただし、フォーム検証をこのメソッドで機能させる方法がわかりませんでした。したがって、それは確かにさらに改善される可能性があります。おそらく、データベースのリファクタリングが最良の長期的な解決策である可能性があることを意味します...
使用するモデル継承の種類によって異なります。 3つの古典的な種類については、http://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritanceを参照 してください。抽象基本クラスを除外するSwallowオブジェクトが必要なように聞こえるので。
Swallow vs AfricanSwallow vs EuropeanSwallowのデータベースにさまざまな情報を保存する場合は、MTIを使用することをお勧めします。公式のdjangoモデルが推奨するMTIの最大の問題は、ポリモーフィズムが適切に機能しないことです。つまり、実際にはAfricanSwallowオブジェクトであるDBからSwallowオブジェクトをフェッチした場合、AfricanSwallowのインスタンスは取得されません。(この質問を参照してください。)django-model-utils InheritanceManagerのようなものは、それを克服するのに役立ちます。
この変更を通じて保持する必要のある実際のデータがある場合は、サウスマイグレーションを使用してください。2つの移行を行います。1つはスキーマを変更し、もう1つは適切なオブジェクトのデータをサブクラスにコピーします。
django-model-utilsのInheritanceCastModelを使用することをお勧めします。これは私が好きな実装の1つです。djangosnippetsやいくつかのブログでさらに多くのことを見つけることができますが、それらをすべて調べた後、私はこれを選びました。それが役に立てば幸い。
別の(時代遅れの)アプローチ:親のIDを保持してもかまわない場合は、親の属性から新しい子インスタンスを作成できます。これは私がしたことです:
ids = [s.pk for s in Swallow.objects.all()]
# I get ids list to avoid memory leak with long lists
for i in ids:
p = Swallow.objects.get(pk=i)
c = AfricanSwallow(att1=p.att1, att2=p.att2.....)
p.delete()
c.save()
これが実行されると、新しいAfricanSwallowインスタンスが作成され、最初の各Swallowインスタンスが置き換えられます。おそらくこれは誰かを助けるでしょう:)