Проверяйте строки перед сохранением модели - PullRequest
6 голосов
/ 09 февраля 2012

Допустим, у меня есть эти две модели:

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

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

И я использую простой TabularInline, чтобы показать Component s внутри Distribution формы администратора:

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

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

Итак, моя цель - проверить, является ли процент всех Component от Distribution суммы 100 перед сохранением. Звучит просто, поэтому я сделал:

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

Но это никогда не сработает, потому что в Django все объекты сохраняются перед сохранением его внешнего ключа или многих связанных объектов, это не недостаток, у него есть причина: он не может сначала сохранить связанные объекты, потому что объект к которым они относятся, еще не определено id (id равно None до тех пор, пока объект не будет сохранен в БД в первый раз).

Я уверен, что я не первый, кто столкнулся с этой проблемой. Итак, есть ли способ выполнить то, что я пытаюсь сделать? Я думал, что, возможно, администраторский хак с использованием TabularInline или ModelAdmin ...?

1 Ответ

3 голосов
/ 09 февраля 2012

Вот (непроверенная) идея, если вы готовы перенести валидацию из модели во встроенный набор форм:

Подкласс BaseInlineFormSet и переопределить метод clean, чтобы проверить сумму процентов.

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

Затем используйте свой встроенный набор форм в ComponentInline.

class ComponentInline(admin.TabularInline):
    model = Component
    extra = 1
    formset = ComponentInlineFormSet
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...