Трясогузка: Динамическая загрузка блоков 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
и построить весь интерфейс редактирования как побочный эффект - это будет смешение логики на уровне модели с кодом интерфейса администратора, и это будет крайне неэффективно только для доступа к одному полю.