Фактически, это проблема добавления программно многих ко многим отношениям при сохранении модели, если вы используете администратора Django.
Django сохраняет отношения m2m в админке, вызывая команду «clear», чтобы стереть ихзатем установите их снова.Это означает, что форма уничтожает любые прикрепленные данные (включая ваши программно присоединенные) к объекту, а затем добавляет те, которые вы ввели в администратор.
Это работает вне администратора, потому что мы не используем форму администратора, которая очищаетотношение m2m.
Причина, по которой это работает для тегов в администраторе, заключается в том, что приложение тегирования не использует m2m, а эмулирует его, помещая объект TaggedItem с внешним ключом в тег и в вашу модель сродовое отношение.Кроме того, это встроенное поле.
Я много чего перепробовал и, наконец, взглянул на исходный код Django, чтобы понять, что Django не обрабатывает формы администратора обычным способом.Что он делает:
- call
ModelAdmin.save_form
: он вызывает form.save
с commit = False
, возвращает несохраненный экземпляр и добавляет в форму метод save_m2m
. - вызов
ModelAdmin.save_model
, который фактически вызывает метод экземпляра save
. - вызов
form.save_m2m
для этого:
- вы не можете переопределить свой
save
метод, так как save_m2m
вызывается после и очищает отношения m2m. - вы не можете переопределить
save_model
по той же причине. - вы не можете переопределить
save_m2m
потому что он добавляется патчем обезьяны к модели формы в form.save
, стирая собственное определение метода.
Я не нашел чистого решения, но кое-что, что работает:
Предоставьте форму для класса ModelAdmin с методом для переопределения save_m2m
с вашим собственным методом:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def set_m2m_method(self, update_tags_and_sites=True):
alias = self.save_m2m
def new_save_m2m(): # this is your new method
alias() # we need to call the original method as well
self.instance.add_niche_sites_and_tags()
self.save_m2m = new_save_m2m # we erase Django erasing :-)
Вызовите этот метод в ModelAdmin.model_save
переопределении:
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
def save_model(self, request, obj, form, change):
obj.save()
form.set_m2m_method()
Это вызывает следующее:
- Джанго звонит
save_model
, заменяя его патч обезьяны на ваш - Джанго звонит нашему
form.save_m2m
, который первымвсе его старый метод, который очищает отношения, а затем прикрепляет m2m к объекту.
Я полностью открыт для любого лучшего способа сделать это, так как это искажено и просто безобразно.