문제

사용자와 프로필을 동시에 추가/편집 할 수 있도록 다음 관리자 설정이 있습니다.

class ProfileInline(admin.StackedInline):
    """
    Allows profile to be added when creating user
    """
    model = Profile


class UserProfileAdmin(admin.ModelAdmin):
    """
    Options for the admin interface
    """
    inlines = [ProfileInline]
    list_display = ['edit_obj', 'name', 'username', 'email', 'is_active',
        'last_login', 'delete_obj']
    list_display_links = ['username']
    list_filter = ['is_active']
    fieldsets = (
        (None, {
            'fields': ('first_name', 'last_name', 'email', 'username',
                'is_active', 'is_superuser')}),
        )
    ordering = ['last_name', 'first_name']
    search_fields = ['first_name', 'last_name']

admin.site.register(User, UserProfileAdmin)

문제는 사용자를 추가 할 때 프로필 인라인 형식의 두 필드가 필요하다는 것입니다. 입력이 입력되지 않으면 인라인 양식이 유효성이 없습니다. 어쨌든 인라인을 필요로하여 비워 둘 수 없습니까?

도움이 되었습니까?

해결책

나는 Carl의 조언을 받아 그의 답변에서 언급 한 Hack-ish를 훨씬 더 나은 구현을 만들었습니다. 내 해결책은 다음과 같습니다.

내 forms.py :

from django.forms.models import BaseInlineFormSet


class RequiredInlineFormSet(BaseInlineFormSet):
    """
    Generates an inline formset that is required
    """

    def _construct_form(self, i, **kwargs):
        """
        Override the method to change the form attribute empty_permitted
        """
        form = super(RequiredInlineFormSet, self)._construct_form(i, **kwargs)
        form.empty_permitted = False
        return form

그리고 관리자

class ProfileInline(admin.StackedInline):
    """
    Allows profile to be added when creating user
    """
    model = Profile
    extra = 1
    max_num = 1
    formset = RequiredInlineFormSet


class UserProfileAdmin(admin.ModelAdmin):
    """
    Options for the admin interface
    """
    inlines = [ProfileInline]
    list_display = ['edit_obj', 'name', 'username', 'email', 'is_active',
        'last_login', 'delete_obj']
    list_display_links = ['username']
    list_filter = ['is_active']
    fieldsets = (
        (None, {
            'fields': ('first_name', 'last_name', 'email', 'username',
                'is_active', 'is_superuser')}),
        (('Groups'), {'fields': ('groups', )}),
    )
    ordering = ['last_name', 'first_name']
    search_fields = ['first_name', 'last_name']


admin.site.register(User, UserProfileAdmin)

이것은 내가 원하는 것을 정확하게 수행하므로 프로파일 인라인 FormSet이 검증됩니다. 따라서 프로파일 양식에 필요한 필드가 있으므로 필요한 정보가 인라인 형식으로 입력되지 않으면 유효성을 검사하고 실패합니다.

다른 팁

이제 django 1.7을 사용하면 매개 변수를 사용할 수 있습니다 min_num. 수업이 필요하지 않습니다 RequiredInlineFormSet 더 이상.

보다 https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.inlinemodeladmin.min_num

class ProfileInline(admin.StackedInline):
    """
    Allows profile to be added when creating user
    """
    model = Profile
    extra = 1
    max_num = 1
    min_num = 1 # new in Django 1.7


class UserProfileAdmin(admin.ModelAdmin):
    """
    Options for the admin interface
    """
    inlines = [ProfileInline]
    ...


admin.site.register(User, UserProfileAdmin)

아마도 이것을 할 수 있지만 Formset/Inline 코드에서 손을 더럽 힐 것입니다.

우선, 나는 당신 이이 경우 FormSet에 항상 하나의 형태가 있고 둘 이상이지 않기를 원한다고 생각하므로 설정하고 싶을 것입니다. max_num= 1과 추가의profileInline에서 = 1.

당신의 핵심 문제는 그 것입니다 baseformset._construct_form은 empty_permitted = true를 통과합니다 FormSet의 각 "extra"(즉, 빈) 형태로. 이 매개 변수는 양식이 변경되지 않은 경우 검증을 우회하도록 지시합니다. 양식에 대해 empty_permitted = false를 설정하는 방법을 찾아야합니다.

당신은 할 수 있습니다 자신의 BaseInlineformset 서브 클래스를 사용하십시오 인라인으로 도움이 될 수 있습니다. _construct_form이 ** kwargs를 사용하고 전달 된 Kwargs를 개별 양식 인스턴스로 무시할 수 있음을 알게되면 Formset 서브 클래스에서 _construct_forms를 무시하고 _construct_form으로 모든 호출에서 emply_permitted = false를 통과 할 수 있습니다. 단점은 내부 API에 의존하고 있다는 것입니다 (_construct_forms를 다시 작성해야합니다).

또는 ProfileInline에서 get_formset 메소드를 재정의하고 부모의 get_formset을 호출 한 후 반환 된 Formset 내부의 양식을 수동으로 포장 할 수 있습니다.

def get_formset(self, request, obj=None, **kwargs):
    formset = super(ProfileInline, self).get_formset(request, obj, **kwargs)
    formset.forms[0].empty_permitted = False
    return formset

주위를 놀아서 일할 수있는 것을보십시오!

가장 쉽고 가장 자연스러운 방법은 Fomset을 통한 것입니다. clean():

class RequireOneFormSet(forms.models.BaseInlineFormSet):
    def clean(self):
        super().clean()
        if not self.is_valid():
            return
        if not self.forms or not self.forms[0].cleaned_data:
            raise ValidationError('At least one {} required'
                                  .format(self.model._meta.verbose_name))

class ProfileInline(admin.StackedInline):
    model = Profile
    formset =  RequireOneFormSet

(에서 영감을 받다 이 Matthew Flanagan의 스 니펫 아래의 Mitar의 의견은 Django 1.11 및 2.0에서 작업하도록 테스트되었습니다.

설정해야합니다 Min_num 인라인 및 validate_min Formset에서.

https://docs.djangoproject.com/en/1.8/topics/forms/formsets/#validate-min

class SomeInline(admin.TabularInline):
    ...
    min_num = 1

    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj=None, **kwargs)
        formset.validate_min = True
        return formset
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top