2010-10-25 8 views
5

Podklasuję istniejący model. Chcę, aby wielu członków klasy rodzicielskiej było teraz członkami klasy dzieci.Przenoszenie obiektu python/django z modelu nadrzędnego do potomka (podklasy)

Na przykład mam model Swallow. Teraz robię EuropeanSwallow (Swallow) i AfricanSwallow (Swallow). Chcę wziąć niektóre, ale nie wszystkie obiekty Swallow, aby były albo EuropeanSwallow, albo AfricanSwallow, w zależności od tego, czy są migracyjne.

Jak mogę je przenieść?

Odpowiedz

4

Wiem, że to dużo później, ale musiałem zrobić coś podobnego i nie mogłem znaleźć wiele. Znalazłem odpowiedź ukrytą w jakimś kodzie źródłowym here, ale napisałem również przykładową metodę klasy, która byłaby wystarczająca.

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 

Nie mogłem się dowiedzieć, jak uzyskać zatwierdzenie formularza do pracy z tą metodą; więc z pewnością można by poprawić więcej; Prawdopodobnie oznacza to, że refaktoryzacja bazy danych może być najlepszym długoterminowym rozwiązaniem ...

+0

Hej - wspaniała odpowiedź. Minęło trochę czasu, odkąd miałem taką potrzebę. Oczywiście jestem trochę niechętny do polegania na _meta w sytuacji produkcyjnej, ale takie jest życie. Dzięki! – jMyles

7

Jest to bit hack, ale to działa:

swallow = Swallow.objects.get(id=1) 
swallow.__class__ = AfricanSwallow 
# set any required AfricanSwallow fields here 
swallow.save() 
+0

Jaki piękny hack, to uratowało mi dzień . Dzięki! – neelix

0

Proponuję za pomocą django-model-utils's InheritanceCastModel. To jedna z realizacji, którą lubię. Możesz znaleźć o wiele więcej na djangosnippetach i na niektórych blogach, ale po przejściu przez nie wszystkie wybrałem tę. Mam nadzieję, że to pomoże.

1

Zależy od rodzaju dziedziczenia modelu, z którego będziesz korzystać. Zobacz http://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance dla trzech klasycznych rodzajów. Ponieważ brzmi to tak, jakbyś chciał połknąć obiekty, które wykluczają abstrakcyjną klasę bazową.

Jeśli chcesz przechowywać różne informacje w db dla Swallow vs AfricanSwallow vs EuropeanSwallow, wtedy będziesz chciał użyć MTI. Największym problemem związanym z MTI jako oficjalnym modelem django jest to, że polimorfizm nie działa prawidłowo. Oznacza to, że jeśli pobierzesz obiekt Swallow z DB, który jest faktycznie obiektem AfricanSwallow, nie dostaniesz instancji o AfricanSwallow. (Patrz this question.) Coś takiego jak django-model-utils InheritanceManager może pomóc przezwyciężyć to.

Jeśli masz rzeczywiste dane, które musisz zachować dzięki tej zmianie, użyj South migrations. Wykonaj dwie migracje - pierwszą, która zmienia schemat, a drugą, która kopiuje dane odpowiednich obiektów do podklas.

0

Inne (przestarzałe) podejście: Jeśli nie masz nic przeciwko zachowaniu identyfikatora rodzica, możesz po prostu stworzyć zupełnie nowe instancje podrzędne z atra rodziców. To, co zrobiłem:

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

Kiedy to działa, nowa instancja AfricanSwallow zostanie utworzony zastępując każde wystąpienie początkowego Jaskółka Może to pomoże ktoś :)

Powiązane problemy