在Wagtail中,我在其中创建了一个ImageChooserBlock
的块,如下所示:
class MyBlock(blocks.StructBlock):
background = ImageChooserBlock()
现在我想在ImageChooserBlock
添加一些额外的字段,所以我把它移到了自己的Block,所以现在它看起来像这样:
class FancyImageChooserBlock(ImageChooserBlock):
extra = blocks.Charfield()
class MyBlock(blocks.StructBlock):
background = FancyImageChooserBlock()
我的第一个问题是extra
字段没有包含在内。 (也许是因为该块继承自ImageChooserBlock
?
我的第二个也是最重要的问题是我希望能够在表单中隐藏额外字段,但包含在模板渲染中。有人知道如何以及如果可能吗?我不想做任何为此注入js或css的hacky东西。必须有一种方法可以使用Blocks
,Widgets
和forms.HiddenInput
或类似的方式执行此操作。
我知道我可以在clean
的{{1}}方法中进行一些计算,以手动设置FancyImageChooserBlock
的值。这正是我想要做的。
感谢任何帮助,我真的被困在这里。
答案 0 :(得分:2)
ImageBlockChooser不喜欢' StructBlock'或者' ListBlock'或者' StreamBlock'这些都是structural block types - 这是为了寻找'您可能定义的任何子字段。只为结构块类型准备了开箱即用的#39;。对于要使用字段的块,需要将其配置为使用/生成具有这些字段的模板。
就我个人而言,我认为有更好的方法来实现你想要的东西而不是子类ImageChooser,因为它通常会更加健壮,试图找到使用Wagtail提供的功能的方法,即使你必须有点创意它们。
但是,如果您仍想通过继承ImageChooser来了解它是如何完成的(黑客入侵):
解决方案1 - 继承ImageChooser(这不是我的首选选项):
#the chooser block class:
class MyImageChooserBlock(ImageChooserBlock):
@cached_property
def widget(self):
from .mywidgetsfolder import MyAdminImageChooser
return MyAdminImageChooser
from wagtail.admin.widgets import AdminChooser
from wagtail.images import get_image_model
#the chooser admin class...
class MyAdminImageChooser(AdminChooser):
"""the only difference between this class and AdminImageChooser
is that this one provides a different template value to
render in the render_to_string method and the addition of certain
variables to the attrs dictionary. You could probably get away
with subclassing AdminImageChooser instead of AdminChooser and just
overriding the render_html method, but for some reason that seemed
to give me a duplicate 'choose image' button and it didn't seem
essential to fix it to demonstrate this principle"""
choose_one_text = _('Choose an image')
choose_another_text = _('Change image')
link_to_chosen_text = _('Edit this image')
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.image_model = get_image_model()
def render_html(self, name, value, attrs):
instance, value = self.get_instance_and_id(self.image_model,
value)
attrs['extra_hidden_fields'] = ('extra_1', 'extra_2')
original_field_html = super().render_html(name, value, attrs)
return render_to_string("my-widgets-folder/my_image_chooser.html", {
'widget': self,
'original_field_html': original_field_html,
'attrs': attrs,
'value': value,
'image': instance,
})
def render_js_init(self, id_, name, value):
return "createImageChooser({0});".format(json.dumps(id_))
#my-widgets-folder/my_image_chooser.html template:
{% extends "wagtailadmin/widgets/chooser.html" %}
{% load wagtailimages_tags %}
{% block chooser_class %}image-chooser{% endblock %}
{% block chosen_state_view %}
{% for a in attrs.extra_hidden_fields %}
<input type="hidden", name={{a}}, value="">
{% endfor %}
<div class="preview-image">
{% if image %}
{% image image max-300x300 class="show-transparency" %}
{% else %}
<img>
{% endif %}
</div>
{% endblock %}
{% block edit_chosen_item_url %}{% if image %}{% url 'wagtailimages:edit' image.id %}{% endif %}{% endblock %}
解决方案2 - 使用自定义结构块和组元值:
当然,使用一些JS / css可以很容易地实现这一点,但假设我们只需要一个html解决方案,就可以实现。
class StructWithHiddenFields(StructBlock):
classMeta:
form_template = "blocks/admin/struct_with_hidden_fields.html"
"""Obviously you'd want to copy the template from the wagtail one
for StructBlocks (wagtailadmin/block_forms/struct.html) to ensure
similar behaviour and then add a bit of logic for the hiding.
This might look like this:"""
#blocks/admin/struct_with_hidden_fields.html template:
<div class="{{ classname }}">
{% if help_text %}
<div class="sequence-member__help help"><span class="icon-
help-inverse" aria-hidden="true"></span>{{ help_text }}
</div>
{% endif %}
<ul class="fields">
{% for child in children.values %}
{% if child.block.meta.group != "hidden-input" %}
<li{% if child.block.required %} class="required"{% endif %}>
{% if child.block.label %}
<label{% if child.id_for_label %} for="{{ child.id_for_label }}"{% endif %}>{{ child.block.label }}:</label>
{% endif %}
{{ child.render_form }}
</li>
{% endif %}
{% endfor %}
</ul>
{% for child in children.values %}
{% if child.block.meta.group == "hidden-input" %}
<input type="hidden" id="{{ prefix }}-{{child.block.label}}" name="{{ prefix }}-{{child.block.label}}" value="{{child.block.value}}">
{% endif %}
{% endfor %}
</div>
#Usage:
class MySpecificBlockWithHiddenFields(StructWithHiddenFields):
normal_field = CharBlock(required=False)
hidden_field = IntegerBlock(required=False, group="hidden-input")
答案 1 :(得分:0)
关于你的第一个问题,为什么不呢:
class MyBlock(blocks.StructBlock):
background = ImageChooserBlock()
extra = blocks.Charfield()
答案 2 :(得分:0)
这个答案不是问题的答案,而是在尝试向后台的ImageChooser
添加一些字段时更好的选择。从Wagtail文档中了解到,有一个叫做Custom Image Model
因此,我没有尝试在Block
&#34;图层&#34;上添加字段,而是将其添加到Model
上。对我来说,代码看起来像这样:
class ImageModel(AbstractImage):
extra = models.CharField(max_length=255, blank=True, null=True)
admin_form_fields = Image.admin_form_fields # So that in the image edit page, the fields are shown
def save(self, **kwargs):
self.clean_extra()
return super(ImageModel, self).save(**kwargs)
def clean_extra(self):
if something():
extra = 'This gets added as an attribute of image'
# Needed for the rendition relation
class ImageRenditionModel(AbstractRendition):
image = models.ForeignKey(ImageModel, related_name='renditions')
class Meta:
unique_together = (
('image', 'filter_spec', 'focal_point_key'),
)
此外,WAGTAILIMAGES_IMAGE_MODEL
必须指向您自己的模型,您可以在文档中找到更多相关信息。
还有另一种方法可以做到这一点,不使用额外的html或额外的模型,但它非常 hacky 和被拒绝。
class FancyImageChooserBlock(ImageChooserBlock):
def clean_extra(self, value):
if something():
value['extra'] = 'This will get rendered in template'
return value
# for rendering in preview
def clean(self, value):
value = super(FancyImageChooserBlock, self).clean(value)
value = self.clean_extra(value)
return value
# for rendering the live view
def to_python(self, value):
value = super(FancyImageChooserBlock, self).to_python(value)
value = self.clean_extra(value)
return value
这样,在添加额外值时,您不需要额外的html, css or js
。这是 disencouraged 的原因是因为它占用了很多用户体验的性能,并且还覆盖了to_python
函数和clean
函数来注入额外的变量非常,非常hacky和脏可能。但是它有效,所以如果你不介意设计标准或性能,单独工作,没有其他人永远看不到你的代码,你可以使用它。
所以不要......