2012-02-09 16 views
6

Diciamo che ho questi due modelli:Convalida inline prima di salvare il modello

class Distribution(models.Model): 
    name = models.CharField(max_length=32) 

class Component(models.Model): 
    distribution = models.ForeignKey(Distribution) 
    percentage = models.IntegerField() 

e sto usando un semplice TabularInline per mostrare Component s all'interno del modulo Distribution admin:

class ComponentInline(admin.TabularInline): 
    model = Component 
    extra = 1 

class DistributionAdmin(admin.ModelAdmin): 
    inlines = [ComponentInline] 

Quindi, il mio obiettivo è quello di convalidare se le percentuali di tutti gli Component s della somma 100 Distribution prima di salvarla. Sembra semplice, così ho fatto:

# ... Inside the Distribution model 
def clean(self): 
    # Sum of components must be 100 
    total_sum = sum(comp.percentage for comp in self.component_set.all()) 
    if total_sum != 100: 
     raise ValidationError('Sum of components must be 100%') 

Ma questo non funzionerà mai il lavoro, perché in Django tutti gli oggetti vengono salvati prima di salvare i suoi oggetti chiave esterna o many2many legati, questo non è un difetto, ha una ragione: non è possibile salvare prima gli oggetti correlati, poiché l'oggetto a cui sono correlati non ha ancora un id definito (id è None finché l'oggetto non viene salvato per la prima volta nel DB).

Sono sicuro di non essere il primo a incorrere in questo problema. Quindi, c'è un modo per realizzare ciò che sto cercando di fare? Stavo pensando forse un hack amministratore utilizzando TabularInline o ModelAdmin ...?

risposta

3

Ecco un (non testato) idea, se sei felice di spostare la convalida dal modello al formset Inline:

sottoclasse BaseInlineFormSet e l'override del metodo pulito per controllare la somma delle percentuali.

from django.forms.models import BaseInlineFormSet 
from django.core.exceptions import ValidationError 

class ComponentInlineFormSet(BaseInlineFormSet): 

    def clean(self): 
     """Check that sum of components is 100%""" 
     if any(self.errors): 
      # Don't bother validating the formset unless each form is valid on its own 
      return 
     total_sum = sum(form.cleaned_data['percentage'] for form in self.forms) 
     if total_sum != 100: 
      raise ValidationError('Sum of components must be 100%') 

quindi utilizzare il formset in linea nella ComponentInline.

class ComponentInline(admin.TabularInline): 
    model = Component 
    extra = 1 
    formset = ComponentInlineFormSet 
+0

Questa è una bella idea! Sapevo che Inline aveva molto da offrire. Ho intenzione di provare questo bene sapere – juliomalegria

+0

fantastico! Ha funzionato bene con un paio di cambiamenti. Grazie, davvero :) – juliomalegria

+0

Felice ha funzionato :) – Alasdair

Problemi correlati