Поле ManyToMany не сохраняется при использовании администратора Django - PullRequest
10 голосов
/ 01 июня 2011

У меня странная проблема, и я надеюсь, что кто-то здесь сможет пролить свет на это.

Я переопределяю метод save () модели, чтобы добавить некоторые значения в поле ManyToMany после запуска super (). Моя проблема в том, что когда я сохраняю в Django admin, значения, кажется, добавляются в отношения, но затем снова пустые.

Если, однако, я делаю это с manage.py shell, это работает без проблем.

Я поместил там два оператора печати, и они выдают одинаковый вывод независимо от того, запускаю ли я его через администратора Django или через оболочку.

class Store(models.Model):
    holidays = models.ManyToManyField(StoreHoliday, blank=True)
    copy_holidays_from = models.ForeignKey('Store', blank=True, null=True)

    def save(self):
        print '====  BEFORE SAVE:', self.holidays.all()
        super(Store, self).save()
        self.copy_holidays()
        print '====  AFTER SAVE:', self.holidays.all()

    def copy_holidays(self):
        if self.pk and self.copy_holidays_from:
            self.holidays.clear()
            for h in self.copy_holidays_from.holidays.all():
                self.holidays.add( h )

Это вывод операторов print:

====  BEFORE SAVE: []
====  AFTER SAVE: [<StoreHoliday: 10 Mar 2010, Chuck Norris birthday (Closed)>]

У кого-нибудь есть предложения по поводу того, что может быть причиной этого?

Редактировать: Кажется, что все ручные изменения отношения m2m в save () игнорируются Django при сохранении через интерфейс администратора. Это связано с тем, как обрабатывается форма?

Ответы [ 5 ]

12 голосов
/ 01 июня 2011

Так что вышеприведенное оказалось не правильным способом его реализации.Код принадлежал StoreAdmin, переопределяя model_save ().

Вот как я это решил:

class StoreAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        if obj.copy_holidays_from:
            form.cleaned_data['holidays'] = obj.copy_holidays_from.holidays.all()

        super(StoreAdmin, self).save_model(request, obj, form, change)
3 голосов
/ 16 сентября 2011

Я, вероятно, столкнулся с таким же поведением только сегодня, и да, вы правы, предполагая, что это связано с тем, как django обрабатывает данные.

Администратор django вносит изменения в поле ManyToMany отдельно от изменения фактическогообъект.(Помните, что m2m сохраняется в другой таблице базы данных).

В моем случае, если я ничего не выбрал в поле ManyToMany на сайте администратора, это вылилось бы в операцию clear () -отношение ManyToMany.Все, что вы делаете в методе save (), сразу удаляется.То же самое с вещами, которые я сделал в обработчике сигнала post_save.

Решение (для меня) состояло в том, чтобы разделить поле ManyToMany на встроенное, чтобы оно не сохранялось как пустое при изменении объекта.

1 голос
/ 24 января 2019

В django 2,1,4 моим решением было использовать save_related ()

def save_related(self, request, form, formsets, change):
    super().save_related(request, form, formsets, change)
    form.instance.permissions.add(request.user)
0 голосов
/ 15 февраля 2019

Одно из решений для обновления m2m, наряду с обновлением одной из ваших моделей.

Django 1.11 and higher

Поведение, которое вы можете наблюдать во время обновления, когда изменения, которые вы сделали с m2mзаписи не были сохранены, даже после того, как вы сделали их в методе сохранения одной из ваших моделей или в сигнале, это происходит только потому, что форма m2m перезаписывает все записи после обновления основного объекта.

Вот почему, шаг за шагомшаг:

  1. Основной объект обновлен.

  2. Ваш код (в методе сохранения или в сигнале) внес изменения (вы можете посмотретьна них просто поставьте точку останова в ModelAdmin):

 def save_related(self, request, form, formsets, change):
     breakpoint()
     form.save_m2m()
     for formset in formsets:
         self.save_formset(request, form, formset, change=change)
form.save_m2m () принимает все значения m2m, которые были размещены на странице (грубо говоря), и заменяет все записи m2m через связанный менеджер.Вот почему вы не можете увидеть свои изменения в конце транзакции.

Существует решение: внесите изменения с помощью m2m с помощью Transactions.on_commit.транзакция.on_commit внесет ваши изменения после form.save_m2m (), когда транзакция будет совершена.

К сожалению, недостаток этого решения - ваши изменения с m2m будут выполнены в отдельной транзакции.*

0 голосов
/ 28 мая 2018

Для меня проблема в том, что администратор сохранял только последний выбранный экземпляр из множества полей (последний выбранный «выходной»). Поэтому мне пришлось переопределить метод save_model, например, такой:

@admin.register(Store)
class StoreAdmin(admin.ModelAdmin):

    def save_model(self, request, obj, form, change):
        form.cleaned_data['holidays'] = StoreHoliday.objects.filter(pk__in=dict(request.POST).get('holidays'))
        super(StoreAdmin, self).save_model(request, obj, form, change)

Я потратил много времени на это, и другие решения не работали, поэтому я надеюсь, что это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...