2012-02-09 15 views
6

Powiedzmy mam te dwa modele:walidacji inlines przed zapisaniem modelu

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

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

i używam prostego TabularInline pokazać Component s wewnątrz postaci Distribution admin:

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

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

Więc, moim celem jest sprawdzenie, czy wartości procentowe wszystkich Component s z sumy 100 przed zapisaniem. Brzmi prosto, tak zrobiłem:

# ... 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%') 

Ale to nigdy nie zadziała pracę, ponieważ w Django wszystkie obiekty są zapisywane przed zapisaniem jej obcy klucz lub many2many podobne obiekty, to nie jest wada, to ma powód: nie może najpierw zapisać powiązanych obiektów, ponieważ obiekt, do którego się odnoszą, nie ma jeszcze zdefiniowanego (id), dopóki obiekt nie zostanie zapisany po raz pierwszy w DB).

Jestem pewien, że nie jestem pierwszym facetem, który wpadł na ten problem. Czy istnieje sposób, aby osiągnąć to, co próbuję zrobić? Myślałem, że może haker z administracji przy użyciu TabularInline lub ModelAdmin ...?

Odpowiedz

3

Oto (niesprawdzone) pomysł, jeśli jesteś szczęśliwy, aby przejść walidację od modelu do formset inline:

Podklasa BaseInlineFormSet i zastąpić czystą metodę sprawdzenia suma procentów.

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%') 

Następnie użyj swojego wbudowanego zestawu formularzy w ComponentInline.

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

To niezły pomysł! Wiedziałem, że Inline ma wiele do zaoferowania. Mam zamiar spróbować tego dobrze znać – juliomalegria

+0

świetnie! Dobrze działało z kilkoma zmianami. Dzięki, naprawdę :) – juliomalegria

+0

Cieszę się, że działało :) – Alasdair

Powiązane problemy