Как мне потребовать встроенный в Django Admin?

У меня есть следующие настройки администратора, чтобы я мог добавлять / редактировать пользователя и его профиль одновременно.

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)

Проблема в том, что мне нужно два поля в встроенной форме профиля, которые требуются при добавлении пользователя. Встроенная форма не проверяется, если ввод не введен. Есть ли какой-либо способ сделать строку необходимой, чтобы ее нельзя было оставить пустой?

Ответы на вопрос(5)

min_num в строке иvalidate_min в форме.

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

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

(Вдохновленныйэтот отрывок Мэтью Фланагана и комментарий Митара ниже, протестированный для работы в Django 1.11 и 2.0).

 13 июн. 2012 г., 22:37
Отлично! Я немного изменил, использовалif not self.is_valid(): вместо того, чтобы вручную проходитьself.errors и использовалself.model._meta.verbose_name.

вероятно, можете сделать это, но вам придется запачкать руки в наборе форм / встроенного кода.

Прежде всего, я думаю, что вы хотите, чтобы в этом случае в наборе форм всегда была одна форма, а не более одной, поэтому вы захотите установитьMAX_NUM= 1 идополнительный= 1 в вашем ProfileInline.

Ваша основная проблема в том, чтоBaseFormSet._construct_form передает empty_permitted = True каждому «дополнительному» (то есть пустой) формы в форме. Этот параметр указывает форме обойти проверку, если она не изменилась. Вам просто нужно найти способ установить empty_permitted = False для формы.

можетеиспользуйте свой собственный подкласс BaseInlineFormset в вашей строке, так что это может помочь. Заметив, что _construct_form принимает ** kwargs и позволяет переопределить kwargs, передаваемые отдельным экземплярам Form, вы можете переопределить _construct_forms в своем подклассе Formset и передать его empty_permitted = False при каждом вызове _construct_form. Недостатком является то, что вы полагаетесь на внутренние API (и вам нужно переписать _construct_forms).

В качестве альтернативы, вы можете попробовать переопределить метод get_formset в своей ProfileInline, и после вызова родительского get_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

Поиграйте и посмотрите, что вы можете сделать работу!

 AJ.31 июл. 2009 г., 18:07
Спасибо за информацию. Я придумал решение, но оно очень хакерское, и я не особо им горжусь. В итоге я переопределил add_view для ModelAdmin и скопировал весь код из представления по умолчанию и изменил значения набора форм. Я собираюсь взглянуть на ваши предложения, чтобы посмотреть, смогу ли я реализовать это более понятным способом. Спасибо за предложения!
Решение Вопроса

чем хакерский, который я упомянул в своем комментарии к его ответу. Вот мое решение:

Из моей формы.

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

И admin.py

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)

Это делает именно то, что я хочу, это делает проверку встроенного набора профилей. Таким образом, поскольку в форме профиля имеются обязательные поля, он будет проверяться и завершаться сбоем, если в встроенную форму не будет введена необходимая информация.

 24 февр. 2012 г., 04:39
Если вы используетеGenericInlineModelAdminзаменитьBaseInlineFormSet сBaseGenericInlineFormSet.
 13 мая 2012 г., 12:16
Спасибо! Однако, если ваша форма не имеет обязательных полей, она все равно не будет проверена и сохранена, когда пуста. Обезьяна-патч формы с помощьюform.has_changed = lambda: True сохранить его, несмотря на то, что он пустой.

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)
 05 дек. 2016 г., 09:13
Подтвердил работу. Благодарю.
 04 авг. 2015 г., 11:12
Подтвердил работу :)
 19 мая 2015 г., 13:53
Это только контролирует количество отображаемых строк. Это не требует, чтобы они были заполнены.
 20 мая 2015 г., 15:55
На самом деле, если inline имеет одно из обязательных полей, он также контролирует заполнение самого inline.
 31 янв. 2017 г., 16:28
Тестирование в 1.10, даже с "min_num" Установка по-прежнему позволяет пользователям выбирать & quot; Удалить & quot; на всех записях, оставляя вас без записей.

Ваш ответ на вопрос