2011-11-28 16 views
12

To pytanie może wyglądać podobnie do this one, ale jej nie ...Zastąp zapisać na Django InlineModelAdmin

Mam strukturę modelu jak:

class Customer(models.Model): 
    .... 

class CustomerCompany(models.Model): 
    customer = models.ForeignKey(Customer) 
    type = models.SmallIntegerField(....) 

Używam InlineModels i mają dwa rodzaje CustomerCampany.type. Więc zdefiniować dwa wypróbujemy inny inline dla CustomerCompany i OV przesłonić InlineModelAdmin.queryset

class CustomerAdmin(admin.ModelAdmin): 
    inlines=[CustomerCompanyType1Inline, CustomerCompanyType2Inline] 


class CustomerCompanyType1Inline(admin.TabularInline): 
    model = CustomerCompany 
    def queryset(self, request): 
     return super(CustomerCompanyType1Inline, self).queryset(request).filter(type=1) 

class CustomerCompanyType2Inline(admin.TabularInline): 
    model = CustomerCompany 
    def queryset(self, request): 
     return super(CustomerCompanyType2Inline, self).queryset(request).filter(type=2) 

Wszystko jest ładne i dobrze się tutaj, ale dla dodawania nowych rekordów do InlineModelAdmin, nadal trzeba wyświetlić type pole CustomerCompany na AdminForm, ponieważ nie mogę zastąpić save sposób na InlineModelAdmin lubię:

class CustomerCompanyType2Inline(admin.TabularInline): 
    model = CustomerCompany 
    def queryset(self, request): 
     return super(CustomerCompanyType2Inline, self).queryset(request).filter(type=2) 
    #Following override do not work 
    def save_model(self, request, obj, form, change): 
     obj.type=2 
     obj.save() 

Korzystanie sygnał nie jest również rozwiązanie, ponieważ mój sygnał sender będzie taka sama Model, więc nie mogę wykryć który InlineModelAdmin wysłać go i co type musi być ...

Czy istnieje sposób, który pozwoli mi ustawić type pole przed uratować?

Odpowiedz

23

Odpowiedź Alasdaira nie jest zła, ale ma kilka bolących punktów, które mogą powodować problemy. Najpierw, przechodząc przez formset, używając form jako nazwy zmiennej, faktycznie przesłonić wartość przekazaną do metody dla form. To nie jest wielka sprawa, ale skoro można zrobić zapis bez zatwierdzenia od samego zestawu, lepiej zrobić to w ten sposób. Po drugie, wszystkie ważne formset.save_m2m() zostały pominięte w odpowiedzi. Rzeczywiste Django docs Zalecamy:

def save_formset(self, request, form, formset, change): 
    instances = formset.save(commit=False) 
    for instance in instances: 
     # Do something with `instance` 
     instance.save() 
    formset.save_m2m() 

Problem masz zamiar uruchomić na to, że metoda save_formset musi iść na rodzica ModelAdmin zamiast inlines, a stamtąd, nie ma sposobu, aby wiedzieć, które inline jest faktycznie wykorzystywany. Jeśli masz obiekt z dwoma "typami" i wszystkie pola są takie same, powinieneś używać modeli proxy i możesz faktycznie zastąpić metodę zapisu każdego z nich, aby ustawić odpowiedni typ automatycznie.

class CustomerCompanyType1(CustomerCompany): 
    class Meta: 
     proxy = True 

    def save(self, *args, **kwargs): 
     self.type = 1 
     super(CustomerCompanyType1, self).save(*args, **kwargs) 

class CustomerCompanyType2(CustomerCompany): 
    class Meta: 
     proxy = True 

    def save(self, *args, **kwargs): 
     self.type = 2 
     super(CustomerCompanyType2, self).save(*args, **kwargs) 

W takim przypadku nie trzeba wykonywać żadnych czynności specjalnych za pomocą maszyn liniowych. Po prostu zmień istniejące wbudowane klasy administracyjne tak, aby używały odpowiedniego modelu proxy, a wszystko się uporządkuje.

+0

+1 dobre podejście używać modeli proxy.Zaktualizowałem swoją odpowiedź, aby naprawić najbardziej oczywiste błędy, o których wspomniałeś. To nadal pozostawia problem z określeniem, który z nich reprezentuje formularz. – Alasdair

+0

W rzeczywistości podejście modelu proxy eliminuje konieczność nadpisywania 'save_formset'. Same proxy zastąpiły metody "save", które wiedzą, jak zapisać jako właściwy typ. Więc po prostu skorzystaj z linii bez martwienia się o to. –

+0

Mój komentarz nie był jednoznaczny - zgodziłem się, że nawet po naprawieniu problemów w 'save_formset' (' save_m2m' itp.), Wciąż istniał problem, który zapisujesz w linii. Zrozumiałem, że podejście modelu proxy unika tego :) – Alasdair

5

Istnieje metoda, którą można przesłonić. Musisz się dowiedzieć, który z nich w jakiś sposób reprezentuje obiekt formset.

def save_formset(self, request, form, formset, change): 
    instances = formset.save(commit=False) 
    for instance in instances: 
     # Do something with `instance` 
     instance.save() 
    formset.save_m2m() 
0

Inne odpowiedzi są właściwe, jeśli chodzi o używanie save_formset. Brakuje im sposobu sprawdzenia, który model jest aktualnie zapisany. Aby to zrobić, można po prostu:

if formset.model == CustomerCompany: 
    # actions for specific model 

co uczyniłoby wygląd funkcji save_formset takiego: (zakładając, że po prostu chcesz zaoszczędzić przesłonić dla konkretnego modelu (ów))

def save_formset(self, request, form, formset, change): 

    # if it's not the model we want to change 
    # just call the default function 
    if formset.model != CustomerCompany: 
     return super(CustomerAdmin, self).save_formset(request, form, formset, change) 

    # if it is, do our custom stuff 
    instances = formset.save(commit=False) 
    for instance in instances: 
     instance.type = 2 
     instance.save() 
    formset.save_m2m() 
Powiązane problemy