Django InlineModelAdmin - установить встроенное поле из запроса на сохранение (установить поле пользователя автоматически) - PullRequest
14 голосов
/ 10 июня 2010

У меня есть две модели, MainModel и связанная InlineModel, которые я хотел бы показать в качестве встроенного в админке.Эта InlineModel может использоваться, например, для создания заметок о модели и должна отслеживать внесенных изменений зарегистрированным пользователем-администратором.Хотя это кажется простым (и действительно, документы показывают пример для этого, когда пользовательское поле является частью MainModel), я не могу понять это, когда поле находится во встроенном.

В частности, моя цель:

  1. Изменения пользователя MainModel
  2. Пользователь добавляет InlineModel, не заполняя поле пользователя
  3. Пользователь нажимает сохранить
  4. Код заполняет поле пользователя для вновь созданных экземпляров InlineModel
  5. (пользовательское поле «Бонус!» Доступно только для существующих экземпляров и скрыто для новых строк)

И мои вопросы:

  1. Это правильно?Слишком базовый save_model не вызывается для экземпляров InlineModelAdmin
  2. Позволяет ли это делать таким образом, чтобы сохранить без возникновения ошибки?(требуется пользователь, проверка помечает его)
  3. Как я могу скрыть поле ввода пользователя для новых строк и сделать его доступным только для существующих строк?

Вот мои текущие идеи:


#models.py
class MainModel(models.Model):
    some_info = models.IntegerField()

class InlineModel(models.Model):
    main = models.ForeignKey(MainModel)
    data = models.CharField(max_length=255)
    user = models.ForeignKey('auth.User')

#admin.py
class InlineModelInline(admin.TabularInline):
    model = InlineModel
    fields = ('data', 'user')
    #readonly_fields = ('data', 'user') #Bonus question later

class MainModelAdmin(admin.ModelAdmin):
    list_display = ('id', 'some_info')
    inlines = [InlineModelInline]

    #def save_model(self, request, obj, form, change):
        #http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
        #Only called for MainModel, not for any of the inlines
        #Otherwise, would be ideal

    def save_formset(self, request, form, formset, change):
        #http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_formset
        #Experimenting showd this is called once per formset (where the formset is a group of inlines)
        #See code block at http://code.djangoproject.com/browser/django/tags/releases/1.2.1/django/contrib/admin/options.py#L894
        if not isinstance(formset.model, InlineModel):
            return super(MainModelAdmin, self).save_formset(request, form, formset, change)
        instances = formset.save(commit=False)
        for instance in instances:
            if not instance.pk:
                instance.user = request.user
        instance.save()
        formset.save_m2m()

Ответы [ 3 ]

9 голосов
/ 10 июня 2010

Я решил первую половину моего вопроса:

def save_formset(self, request, form, formset, change):
    if formset.model != InlineModel:
        return super(MainModelAdmin, self).save_formset(request, form, formset, change)
    instances = formset.save(commit=False)
    for instance in instances:
        if not instance.pk:
            instance.user = request.user
        instance.save()
    formset.save_m2m()

Теперь меня интересует бонусное поведение:

  1. Я должен выбрать пользователя при добавлении нового встроенного из-за правил проверки. Мое лучшее предположение - не включать поле 'user' в мой кортеж InlineModelInline.fields, но тогда это не покажет автора для существующих экземпляров InlineModel. (Редактировать: добавление 'user' в readonly_fields работает здесь)

  2. (Правка) Как я могу сделать так, чтобы существующие inline отображали «данные» только для чтения, но при этом могли редактировать их при добавлении нового inline?

1 голос
/ 07 июня 2016

Это сработало для меня. Этот подход не позволяет мне удалять встроенные элементы.

def save_formset(self, request, form, formset, change):
    for form in formset.forms:
        form.instance.user = request.user
    formset.save()
0 голосов
/ 10 сентября 2016

Чтобы ответить на дополнительный вопрос: «Как сделать так, чтобы существующие встроенные файлы отображали« данные »только для чтения, но при этом могли редактировать их при добавлении новых встроенных файлов?»:

Я использую две строки для одной и той же модели:

#admin.py
class InlineModelInline(admin.TabularInline):
    model = InlineModel
    extra = 1
    max_num = 1

#admin.py
class InlineModelExistingInline(admin.TabularInline):
    model = InlineModel
    readonly_fields = ('data', 'user') #All Fields here except pk
    can_delete = False
    extra = 0
    max_num = 0

class MainModelAdmin(admin.ModelAdmin):
    ...
    inlines = [InlineModelInline, InlineModelExistingInline]
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...