Django InlineModelAdmin-установить встроенное поле из запроса на сохранение (установить поле пользователя автоматически) (сохранить formset vs сохранить модель)

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

чтобы быть конкретным, моя цель:

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

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

  1. это правильно? Его слишком bas 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 ответов


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

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. Я должен выбрать пользователя при добавлении нового встроенного из-за правил проверки. Мое лучшее предположение-не включать поле "пользователь" в мою InlineModelInline.кортеж полей, но тогда это не покажет автора для существующих экземпляров InlineModel. (Edit: добавление "user" в readonly_fields работает здесь)

  2. (Edit) как я могу сделать существующие строки отображаемыми "данными"только для чтения, но все же иметь возможность редактировать их при добавлении новой строки?


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

def save_formset(self, request, form, formset, change):
    for form in formset.forms:
        form.instance.user = request.user
    formset.save()

чтобы ответить на бонусный вопрос: "Как я могу сделать существующие строки рендеринга "данные" только для чтения, но все же иметь возможность редактировать его при добавлении новой строки?":

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

#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]
    ...