Заменить сохранение в Django InlineModelAdmin
Этот вопрос может выглядеть как этот, но его не...
У меня есть модельная структура вроде:
class Customer(models.Model):
....
class CustomerCompany(models.Model):
customer = models.ForeignKey(Customer)
type = models.SmallIntegerField(....)
Я использую InlineModels
и имею два типа CustomerCampany.type
. Поэтому я определяю два разных строковых значения для CustomerCompany
и ov override InlineModelAdmin.queryset
class CustomerAdmin(admin.ModelAdmin):
inlines=[CustomerCompanyType1Inline, CustomerCompanyType2Inline]
class CustomerCompanyType1Inline(admin.TabularInline):
model = CustomerCompany
def queryset(self, request):
return super(CustomerCompanyType1Inline, self).queryset(request).filter(type=1)
class CustomerCompanyType2Inline(admin.TabularInline):
model = CustomerCompany
def queryset(self, request):
return super(CustomerCompanyType2Inline, self).queryset(request).filter(type=2)
Все хорошо и хорошо, но для добавления новых записей для InlineModelAdmin
мне все равно нужно отобразить type
поле CustomerCompany
на AdminForm
, так как я не могу переопределить метод save
от InlineModelAdmin
как:
class CustomerCompanyType2Inline(admin.TabularInline):
model = CustomerCompany
def queryset(self, request):
return super(CustomerCompanyType2Inline, self).queryset(request).filter(type=2)
#Following override do not work
def save_model(self, request, obj, form, change):
obj.type=2
obj.save()
Использование сигнала также не является решением, так как мой сигнал sender
будет таким же Model
, поэтому я не могу определить, какой InlineModelAdmin
отправить его, а что type
должно быть...
Есть ли способ, который позволит мне установить поле type
перед сохранением?
Ответы
Ответ 1
Ответ Alasdair не ошибается, но у него есть несколько серьезных проблем, которые могут вызвать проблемы. Во-первых, путем прокрутки набора форм с использованием form
в качестве имени переменной вы фактически переопределяете значение, переданное в метод для form
. Это не огромная сделка, но поскольку вы можете сделать сохранение без фиксации прямо из набора форм, лучше сделать это именно так. Во-вторых, все важные formset.save_m2m()
были исключены из ответа. Фактические Django docs рекомендуют следующее:
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for instance in instances:
# Do something with `instance`
instance.save()
formset.save_m2m()
Проблема, с которой вы столкнетесь, заключается в том, что метод save_formset
должен идти по родительскому ModelAdmin
, а не по строкам, а оттуда нет способа узнать, какая строка используется. Если у вас есть obj с двумя "типами", и все поля одинаковы, вы должны использовать прокси-модели, и вы можете фактически переопределить метод сохранения каждого, чтобы автоматически установить соответствующий тип.
class CustomerCompanyType1(CustomerCompany):
class Meta:
proxy = True
def save(self, *args, **kwargs):
self.type = 1
super(CustomerCompanyType1, self).save(*args, **kwargs)
class CustomerCompanyType2(CustomerCompany):
class Meta:
proxy = True
def save(self, *args, **kwargs):
self.type = 2
super(CustomerCompanyType2, self).save(*args, **kwargs)
Затем вам не нужно делать ничего особенного с вашими строками. Просто измените существующие классы встроенных админов, чтобы использовать их подходящую прокси-модель, и все будет сортировать себя.
Ответ 2
Здесь save_formset
метод, который вы можете переопределить. Вам нужно будет решить, какая строка formset
представляет как-то.
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for instance in instances:
# Do something with `instance`
instance.save()
formset.save_m2m()
Ответ 3
Другие ответы правильны, когда дело доходит до использования save_formset. У них отсутствует способ проверить, какая модель в настоящее время сохраняется. Для этого вы можете просто:
if formset.model == CustomerCompany:
# actions for specific model
Что бы сделать функцию save_formset такой: (предполагая, что вы просто хотите переопределить сохранение для конкретной модели (моделей))
def save_formset(self, request, form, formset, change):
# if it not the model we want to change
# just call the default function
if formset.model != CustomerCompany:
return super(CustomerAdmin, self).save_formset(request, form, formset, change)
# if it is, do our custom stuff
instances = formset.save(commit=False)
for instance in instances:
instance.type = 2
instance.save()
formset.save_m2m()