ValidationError при изменении объекта с помощью встроенного администратора

У меня есть модель Position с полем ForeignKey, связанным с моделью Emplacement . В admin Emplacement я установил Inline admin для Position .

Я хочу добиться того, что когда поле num_position изменено в экземпляре Emplacement , позиции, связанные с этим экземпляром, удаляются, а новые создаются.

Для этого я переопределяю метод Emplacement save() и проверяю, изменился ли num_position .

Проблема заключается в том, что при сохранении модели Emplacement после изменения поля num_position появляется следующее сообщение об ошибке:

ValidationError: Select a valid choice. That choice is not one of the available choices.

Я предполагаю, что это связано с удалением/восстановлением позиций, но я не могу найти почему.

Что не так?

<Б> models.py

class Emplacement(models.Model): 

    num_position = models.IntegerField()
    # more fields

    __original_num_position = None

    def __init__(self, *args, **kwargs):
        super(Emplacement, self).__init__(*args, **kwargs)
        self.__original_num_position = self.num_position

    def save(self, *args, **kwargs):

        if self.num_position != self._Emplacement__original_num_position:
            # if num_position has changed, delete existing positions and recreate  positions
            Position.objects.filter(emplacement=self).delete()            
            for i in range(self.num_position):
                position = Position()
                position.emplacement = self
                position.number = i+1
                position.save()

        super(Emplacement, self).save(*args, **kwargs)

class Position(models.Model):
    emplacement = models.ForeignKey(Emplacement)
    number = models.IntegerField()

<Б> admin.py

class PositionInline(admin.TabularInline):
    model = Position

class EmplacementAdmin(admin.ModelAdmin):
    inlines = [PositionInline]

my_site.register(Emplacement, EmplacementAdmin)

ИЗМЕНИТЬ

Я также попытался с сигналом, но получил ту же ошибку:

@receiver(post_save, sender=Emplacement)
def create_positions(sender, instance, created, **kwargs):
    """Create positions when num_position has changed."""
    if instance.num_position != instance.old_num_position:
        Position.objects.filter(emplacement=instance).delete()
        for i in range(instance.num_position):
            position = Position()
            position.emplacement = instance
            position.numero = i+1            
            position.save()
0
nl ja de
Я просто попытался создать новый проект django и вставить этот код в приложение. Я не вижу никаких ошибок при создании/сохранении объектов Emplacement/Position. Вы видите исключение при запуске только этого кода или есть какой-то конкретный способ вызвать ошибку?
добавлено автор Nathan Jhaveri, источник

1 ответы

Я столкнулся с той же проблемой. Наконец, решил это, не внедряя логику create/delete на стороне модели, а в Формах/Формах.

Поэтому в «главном» классе администратора в вашем случае «EmplacementAdmin» расширен метод save_formset:

def save_formset(self, request, form, formset, change):
    instance = form.instance
    deleted = []
    if instance and instance.__original_num_position != instance.num_position:
        ''' create new Positions if needed '''

        formset.delete_positions = None # pass on a list, QuerySet, whatever

    super(EmplacementAdmin, self).save_formset(request, form, formset, change)

И создайте PositionFormSet так:

class PositionFormSet(BaseInlineFormSet):
    delete_positions = []

    @property
    def deleted_forms(self):
        deleted_forms = []
        try:
            deleted_forms = super(PositionFormSet, self).deleted_forms
        except AttributeError:
            pass
        for form in self.forms:
            if form.instance in self.delete_positions:
                 deleted_forms.append(form)
        self.delete_positions = []
        return deleted_forms

И установите этот набор форм в свой inlineadmin:

class PositionInline(admin.TabularInline):
    model = Position
    formset = PositionFormSet

Не совсем так, как я имел в виду, но трюк сработал для меня. Любопытно узнать, есть ли еще более элегантные решения :-)

1
добавлено
Django
Django
1 931 участник(ов)

Полезная информация и правила: https://github.com/django-ru/faq Вакансии и резюме: @django_jobs Пофлудить идём сюда: @django_flood Статистика чата: combot.org/chat/-1001063854692

django_jobs
django_jobs
916 участник(ов)

Поиск и предложения работы (Django) Правила: https://t.me/django_jobs/4 Вакансии с тегом #job улетают в канал @django_jobs_board Вопросы к @amureki Основной чат @pydjango

Django
Django
733 участник(ов)

Веб-фреймворк для перфекционистов с дедлайнами. Наша группа на vk: https://vk.com/django_framework В Discord: https://discord.me/django_framework по всем вопросам @MechanisM

django flood
django flood
71 участник(ов)

Флудилка джангистов Пока без правил