2011-11-28 13 views
12

Tale questione potrebbe essere simile a this one, ma la sua non ...Override risparmiare sulle Django InlineModelAdmin

Ho una struttura di modello come:

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

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

Sto usando InlineModels, e hanno due tipi di CustomerCampany.type. Così mi definisco due in linea differente per la CustomerCompany e OV sovrascrivo 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) 

Tutto è bello e buono fino a qui, ma per l'aggiunta di nuovi record per InlineModelAdmin, ho ancora bisogno di visualizzare type campo CustomerCompany sul AdminForm, poiché non posso ignorare save metodo di un InlineModelAdmin piacere:

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

Utilizzando un segnale non è anche una soluzione dal mio segnale sender sarà lo stesso Model, quindi non in grado di rilevare che InlineModelAdmin inviarlo e quale deve essere il type ...

C'è un modo che mi permetta di impostare type campo prima di salvare?

risposta

23

La risposta di Alasdair non è sbagliata, ma presenta alcuni punti dolorosi che potrebbero causare problemi. Innanzitutto, eseguendo il looping attraverso il formset utilizzando form come nome della variabile, in realtà si sostituisce il valore passato nel metodo per form. Non è un grosso problema, ma dal momento che si può fare il salvataggio senza commettere direttamente dal formset, è meglio farlo in questo modo. Secondo, l'importante formset.save_m2m() è stato lasciato fuori dalla risposta. I Django docs attuali raccomandano le seguenti:

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

Il problema si sta andando a correre in è che il metodo save_formset deve andare avanti il ​​genitore ModelAdmin piuttosto che gli inline, e da lì, non c'è modo di sapere quale linea viene effettivamente utilizzato. Se hai un oggetto con due "tipi" e tutti i campi sono uguali, allora dovresti usare i modelli proxy e puoi effettivamente sovrascrivere il metodo di salvataggio di ciascuno per impostare automaticamente il tipo appropriato.

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) 

Quindi, non è necessario fare nulla di speciale con il tuo inline. È sufficiente modificare le classi di amministrazione in linea esistenti per utilizzare il proprio modello proxy appropriato e tutto verrà risolto automaticamente.

+0

+1 buon approccio usare i modelli proxy.Ho aggiornato la mia risposta per correggere gli errori più ovvi che hai menzionato. Ciò lascia ancora il problema di capire quale inline rappresenta il formset. – Alasdair

+0

In realtà, l'approccio del modello proxy elimina la necessità di sovrascrivere 'save_formset'. I proxy stessi hanno sovrascritto i metodi 'save' che sanno come salvare il tipo giusto. Quindi, usi semplicemente la linea inline senza preoccuparti di ciò. –

+0

Il mio commento non era chiaro - ero d'accordo sul fatto che anche dopo aver risolto i problemi in 'save_formset' (' save_m2m' etc), c'era ancora il problema di quale linea si sta salvando. Ho capito che l'approccio al modello proxy evita quello :) – Alasdair

5

C'è un metodo save_formset che è possibile sovrascrivere. Dovresti capire quale in linea lo formset rappresenta in qualche modo.

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

Altre risposte sono giuste quando si tratta di utilizzare save_formset. Mancano però un modo per verificare quale modello è attualmente salvato. Per fare questo, si può solo:

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

che renderebbe l'aspetto funzione di save_formset come: (supponendo che si desidera solo per sovrascrivere salvare per il modello specifico (s))

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