我繼承現有的模型。現在我想讓許多父類的成員成爲子類的成員。移動從父模型蟒蛇/ Django的對象一個孩子(子類)
例如,我有一個模型燕子。現在,我正在製作EuropeanSwallow(燕子)和AfricanSwallow(燕子)。我想採取一些但不是所有的燕子物體,使它們成爲歐洲流氓或非洲流氓,這取決於它們是否是遷徙。
我該如何移動它們?
我繼承現有的模型。現在我想讓許多父類的成員成爲子類的成員。移動從父模型蟒蛇/ Django的對象一個孩子(子類)
例如,我有一個模型燕子。現在,我正在製作EuropeanSwallow(燕子)和AfricanSwallow(燕子)。我想採取一些但不是所有的燕子物體,使它們成爲歐洲流氓或非洲流氓,這取決於它們是否是遷徙。
我該如何移動它們?
我知道這是晚得多,但我需要做同樣的事情,找不到了。我在一些源代碼here中找到了答案,但也寫了一個示例類方法就足夠了。
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
我找不出如何讓我的表單驗證使用這種方法,但是;所以肯定可以進一步改善;可能意味着一個數據庫重構可能是最好的長期解決方案...
這是一個黑客攻擊的一位,但這個工程:
swallow = Swallow.objects.get(id=1)
swallow.__class__ = AfricanSwallow
# set any required AfricanSwallow fields here
swallow.save()
多麼美麗的黑客,它救了我的一天。謝謝! – neelix 2016-11-16 07:46:25
我建議使用django-model-utils's InheritanceCastModel。這是我喜歡的一個實現。你可以在djangosnippets和一些博客中找到更多,但是通過它們之後,我選擇了這一個。希望能幫助到你。
要看你會用什麼樣的模式繼承。請參閱 http://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance 三種經典種類。因爲它聽起來像你想要排除抽象基類的Swallow對象。
如果你想不同的信息存儲在數據庫中的燕子VS AfricanSwallow VS EuropeanSwallow,那麼你要使用MTI。 MTI作爲官方django模型推薦的最大問題是多態性無法正常工作。也就是說,如果你從數據庫中獲取一個實際上是AfricanSwallow對象的Swallow對象,那麼你將不會得到一個非洲流氓實例。 (請參閱this question。)類似django-model-utils InheritanceManager可以幫助解決這個問題。
如果您有需要通過這種變化以保持實際的數據,使用South migrations。進行兩次遷移 - 第一次更改模式,另一次將相應對象的數據複製到子類中。
另一個(過時)的方法:如果你不介意保持一方的身份證你可以創建一個從父母的ATTRS全新的子實例。這是我做過什麼:
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實例將被創建替換每個初始燕子實例 也許這將幫助別人:)
嘿 - 真棒的答案。自從我有這種需求已經有一段時間了。當然,在生產環境中,我有點不願依靠_meta,但這就是生活。謝謝! – jMyles 2014-01-16 02:53:58