Условный Inline в админской панели Django - ошибка "ManagementForm data is missing or has been tampered with"
Основной текст заметки
Иногда требуется делать условный Inline. как его сделать - много где описано - но в ситуации когда условие отображения инлайна изменяется в процессе редактирования, вылезает ошибка `ManagementForm data is missing or has been tampered with`
Что бы ее избежать приходится сохранять значение атрибута и использовать его при проверке.
Ниже приведен пример
Программный код
============== admin.py ============== class CharacterAdmin(admin.ModelAdmin): model = Character inlines = [CharacterValueInline] prepopulated_fields = {"handle": ("internal_name",), "public_name": ("internal_name",)} def get_inline_instances(self, request, obj:Character=None): inline_instances = [] for inline_class in self.get_inlines(request, obj): inline = inline_class(self.model, self.admin_site) if request: if not obj or obj._original_character_type != obj.CHARACTER_TYPE_SET: continue if not (inline.has_view_or_change_permission(request, obj) or inline.has_add_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request, obj): inline.max_num = 0 inline_instances.append(inline) return inline_instances def get_formsets_with_inlines(self, request, obj:Character=None): for inline in self.get_inline_instances(request, obj): # hide/show market-specific inlines based on market name if obj and obj._original_character_type == obj.CHARACTER_TYPE_SET: yield inline.get_formset(request, obj), inline ============== models.py ============== class Character(models.Model): """ Класс реализует характеристики товара """ class Meta: verbose_name = _('Character') verbose_name_plural = _('Characters') app_label = 'store' internal_name = models.CharField( max_length=100, null=False, blank=False, unique=True, verbose_name=_('Internal character name'), ) handle = models.SlugField( max_length=32, null=False, blank=False, unique=True, verbose_name=_('Hadle'), help_text=_('case insensitive') ) public_name = models.CharField( max_length=100, null=True, blank=True, verbose_name=_('Public character name'), ) name = property(lambda self:self.public_name if self.public_name else self.internal_name) CHARACTER_TYPE_INHERITED = 0x1000 CHARACTER_TYPE_INTEGER = 0x0001 CHARACTER_TYPE_FLOAT = 0x0002 CHARACTER_TYPE_DECIMAL = 0x0003 CHARACTER_TYPE_SET = 0x0004 CHARACTER_TYPES = ( (CHARACTER_TYPE_INTEGER, _('Integer value')), (CHARACTER_TYPE_FLOAT, _('Float value')), (CHARACTER_TYPE_DECIMAL, _('Fixed decimal value')), (CHARACTER_TYPE_SET, _('Set of string values')), ) _original_character_type = None character_type = models.IntegerField( null=False, blank=False, default=CHARACTER_TYPE_INTEGER, choices=CHARACTER_TYPES ) def __init__(self, *args, **kwargs): super(Character, self).__init__(*args, **kwargs) self._original_character_type = self.character_type def save(self, force_insert=False, force_update=False, using=None, update_fields=None): self.handle = self.handle.upper() # Переводим значение в верхний регистр return super().save(force_insert, force_update, using, update_fields) def __str__(self): return self.internal_name
Заметка написана: 25.05.2020
Теги заметки: Django