Django: заполнение полей InlineModelAdmin из объекта request

Конструируя с использованием Django типовой интерфейс на основе ModelAdmin, иногда важно инициализировать некоторое поле модели из InlineModelAdmin значением, полученным из объекта request. На первый взгляд, задача элементарная, но не спешите с выводами.

Предположим, в Django 1.11 необходимо назначить текущего пользователя владельцем некоторого экземпляра модели. Сигнал pre_save, посылаемый перед сохранением модели, использовать нельзя: текущий пользователь доступен только через объект request, к которому нельзя обратиться через чистые функции модели.

Возможный выход — переопределить метод ModelAdmin.save_formset().

Решение

def save_formset(self, request, form, formset, change):
    if formset.model != WorklogInlineAdmin.model:
        return super().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()

    for obj in formset.deleted_objects:
        obj.delete()

    formset.save_m2m()

Что происходит?

ModelAdmin.save_formset() обрабатывает все InlineModelAdmin, определенные в атрибуте ModelAdmin.inlines. Поскольку логика автодобавления текущего пользователя необходима не для всех InlineModelAdmin (в примере — WorklogInlineAdmin), выполняется проверка:

formset.model != WorklogInlineAdmin.model

В последующем коде выполняется присоединение объекта текущего пользователя к экземпляру модели, удаление отмеченных объектов и сохранение полей типа «многие-ко-многим».