Трясогузка: Динамическая загрузка блоков StreamField в админском EditView

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

Я перерыл код FieldPanel, StreamBlock и GroupPanel и не могу четко найти способ переопределить доступные блоки для StreamField вне определения модели.

Это моя текущая админка EditView, где вы можете увидеть, чего я пытаюсь достичь (см. NOTE/FIXME комментарии ниже:

).
class EditProductView(EditView):

    def get_edit_handler(self):
        summary_panels = [
            FieldPanel('title'),
            FieldPanel('description'),
            FieldPanel('body'),
        ]

        attributes_panel = [
            # NOTE/FIXME: This is where we need the custom blocks to load, based
            # on `self.instance.product_type`.

            FieldPanel('attributes'),

            # StreamFieldPanel (which is deprecated) does not work because you can
            # only set the blocks within the model, when defining the StreamFieldPanel.
            # I would love to be able to do something like:

            StreamFieldPanel('attributes', block_types=[
                ('test', blocks.CharBlock()),   # Like this for example
            ])

        ]

        settings_panels = [
            FieldPanel('categories'),
            StateMachinePanel('state', sm_prop='sm', heading="State"),
        ]

        return TabbedInterface([
            ObjectList(summary_panels, heading='Summary'),
            ObjectList(attributes_panel, heading='Attributes'),
            ObjectList(settings_panels, heading='Settings'),
        ]).bind_to_model(self.model_admin.model)

Возможно ли переопределить доступные блоки StreamField таким образом, или есть потенциальные проблемы с json_field целостностью БД?

Это не сработает, потому что определение блока StreamField используется не только для формы редактирования - всякий раз, когда вы обращаетесь к этому полю, даже просто для вывода его в шаблоне, StreamField должен посмотреть на определение блока, чтобы распаковать JSON и вернуть соответствующие объекты Python. Например, предположим, что база данных содержит:

[{'type': 'test', 'value': 123}]

Что должно возвращать page.attributes[0].value? Если блок test имеет тип IntegerBlock, он вернет 123 - но если бы вместо него был PageChooserBlock, он вернет экземпляр Page с ID 123. Если бы это был ImageChooserBlock, он бы вернул экземпляр Image с ID 123, и так далее. В вашем примере единственный способ узнать тип блока - это вызвать get_edit_handler и построить весь интерфейс редактирования как побочный эффект - это будет смешение логики на уровне модели с кодом интерфейса администратора, и это будет крайне неэффективно только для доступа к одному полю.

Вернуться на верх