복붙노트

[PYTHON] 장고 관리자의 종속 인라인의 유효성 검사

PYTHON

장고 관리자의 종속 인라인의 유효성 검사

Django 1.4를 사용하고 있으며 서로 다른 인라인 값을 비교하는 유효성 검사 규칙을 설정하려고합니다.

나에게는 세 가지 간단한 수업이있다.

models.py에서 :

class Shopping(models.Model):
    shop_name = models.CharField(max_length=200)

class Item(models.Model):
    item_name = models.CharField(max_length=200)
    cost = models.IntegerField()
    item_shop = models.ForeignKey(Shopping)

class Buyer(models.Model):
    buyer_name = models.CharField(max_length=200)
    amount = models.IntegerField()
    buyer_shop = models.ForeignKey(Shopping)

admin.py :

class ItemInline(admin.TabularInline):
    model = Item

class BuyerInline(admin.TabularInline):
    model = Buyer

class ShoppingAdmin(admin.ModelAdmin):
    inlines = (ItemInline, BuyerInline)

예를 들어 10 $의 럼주 한 병과 8 $의 보드카 한 병을 구입할 수 있습니다. Mike는 15 달러를, Tom은 3 달러를 지불합니다.

목표는 사용자가 일치하지 않는 인스턴스를 저장하지 못하도록하는 것입니다. 지불 된 항목은 항목 비용의 합계 (예 : 10 + 8 = 15 + 3)와 같아야합니다.

나는 시도했다 :

이 문제에 대한 해결책이 있습니까? 클라이언트 측 (javascript / ajax) 유효성 검사가 가장 간단합니까?

해결법

  1. ==============================

    1.원하는 것을 얻기 위해 인라인 formset을 재정의 할 수 있습니다. formset의 정리 메소드에서 'instance'멤버를 통해 Shopping 인스턴스에 액세스 할 수 있습니다. 따라서 Shopping 모델을 사용하여 계산 된 총계를 임시로 저장하고 서식 세트를 통신 할 수 있습니다. models.py에서 :

    원하는 것을 얻기 위해 인라인 formset을 재정의 할 수 있습니다. formset의 정리 메소드에서 'instance'멤버를 통해 Shopping 인스턴스에 액세스 할 수 있습니다. 따라서 Shopping 모델을 사용하여 계산 된 총계를 임시로 저장하고 서식 세트를 통신 할 수 있습니다. models.py에서 :

    class Shopping(models.Model):
       shop_name = models.CharField(max_length=200)
    
       def __init__(self, *args, **kwargs)
           super(Shopping, self).__init__(*args, **kwargs)
           self.__total__ = None
    

    admin.py :

    from django.forms.models import BaseInlineFormSet
    class ItemInlineFormSet(BaseInlineFormSet):
       def clean(self):
          super(ItemInlineFormSet, self).clean()
          total = 0
          for form in self.forms:
             if not form.is_valid():
                return #other errors exist, so don't bother
             if form.cleaned_data and not form.cleaned_data.get('DELETE'):
                total += form.cleaned_data['cost']
          self.instance.__total__ = total
    
    
    class BuyerInlineFormSet(BaseInlineFormSet):
       def clean(self):
          super(BuyerInlineFormSet, self).clean()
          total = 0
          for form in self.forms:
             if not form.is_valid():
                return #other errors exist, so don't bother
             if form.cleaned_data and not form.cleaned_data.get('DELETE'):
                total += form.cleaned_data['cost']
    
          #compare only if Item inline forms were clean as well
          if self.instance.__total__ is not None and self.instance.__total__ != total:
             raise ValidationError('Oops!')
    
    class ItemInline(admin.TabularInline):
       model = Item
       formset = ItemInlineFormSet
    
    class BuyerInline(admin.TabularInline):
       model = Buyer
       formset = BuyerInlineFormSet
    

    이것은 당신이 그것을 할 수있는 유일한 깨끗한 방법입니다 (제 지식의 최상). 그리고 모든 것이 그것이 있어야하는 곳에 위치합니다.

    편집 : form.cleaned_data * check 양식에 빈 인라인이 포함되어 있기 때문에 *를 추가했습니다. 이것이 어떻게 효과가 있는지 알려주세요!

    EDIT2 : 주석에 정확하게 지적한 바와 같이, 삭제 될 양식에 대한 점검을 추가했습니다. 이 양식들은 계산에 참여해서는 안됩니다.

  2. ==============================

    2.좋아, 나는 해결책이있다. 그것은 장고 관리자의 코드를 편집이 포함됩니다.

    좋아, 나는 해결책이있다. 그것은 장고 관리자의 코드를 편집이 포함됩니다.

    django / contrib / admin / options.py의 add_view (924 줄) 및 change_view (1012 줄) 메소드에서 다음 부분을 찾으십시오.

            [...]
            if all_valid(formsets) and form_validated:
                self.save_model(request, new_object, form, True)
            [...]
    

    그것을

            if not hasattr(self, 'clean_formsets') or self.clean_formsets(form, formsets):
                if all_valid(formsets) and form_validated:
                    self.save_model(request, new_object, form, True)
    

    이제 ModelAdmin에서 다음과 같이 할 수 있습니다.

    class ShoppingAdmin(admin.ModelAdmin):
        inlines = (ItemInline, BuyerInline)
        def clean_formsets(self, form, formsets):
            items_total = 0
            buyers_total = 0
            for formset in formsets:
                if formset.is_valid():
                    if issubclass(formset.model, Item):
                        items_total += formset.cleaned_data[0]['cost']
                    if issubclass(formset.model, Buyer):
                        buyers_total += formset.cleaned_data[0]['amount']
    
            if items_total != buyers_total:
                # This is the most ugly part :(
                if not form._errors.has_key(forms.forms.NON_FIELD_ERRORS):
                    form._errors[forms.forms.NON_FIELD_ERRORS] = []
                form._errors[forms.forms.NON_FIELD_ERRORS].append('The totals don\'t match!')
                return False
            return True
    

    이것은 적절한 해결책보다 더 해킹입니다. 어떤 개선 제안? 아무도 이것이 장고에 대한 기능 요청이어야한다고 생각합니까?

  3. from https://stackoverflow.com/questions/13526792/validation-of-dependant-inlines-in-django-admin by cc-by-sa and MIT license