把***块藏在华泰

2024-06-02 06:25:57 发布

您现在位置:Python中文网/ 问答频道 /正文

在Wagtail中,我制作了一个包含ImageChooserBlock的块,如下所示:

class MyBlock(blocks.StructBlock):
    background = ImageChooserBlock()

现在我想向ImageChooserBlock添加一些额外的字段,所以我将它移动到它自己的块中,现在看起来像这样:

^{pr2}$

我的第一个问题是extra字段没有包括在内。(可能是因为块继承了ImageChooserBlock?在

我的第二个也是最重要的问题是,我希望能够在表单中隐藏额外的字段,但要包含在模板呈现中。有人知道这是怎么做到的吗?我不想为此注入js或css。必须有一种方法可以使用BlocksWidgets和{}或类似的方法。在

我知道我可以在我的FancyImageChooserBlockclean方法中进行一些计算来手动设置extra的值。这正是我想做的。在

任何帮助都是感激的,我真的被困在这里了。在


Tags: 方法模板表单jsextracssclasswagtail
3条回答

ImageBlockChooser不像'StructBlock'或'ListBlock'或'StreamBlock',它们都是structural block types-这是为了“查找”您可能定义的任何子字段而设计的。只有结构块类型是为“开箱即用”准备的。对于要使用字段的块,需要将其配置为使用/生成包含这些字段的模板。在

就个人而言,我认为有更好的方法来实现您想要的,而不是子类化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-使用自定义结构块和组元值:

  • 此解决方案使用自定义结构块来隐藏字段和标签。我现在推荐这种方法,因为它使用wagtail提供的定制功能供您使用。虽然文档中没有提到以这种方式使用组meta,但是组meta是有文档记录的,并且应该可以依赖(如果需要,它可能很容易被另一个细节代替)。在
  • 对于任何人在这个答案上发生的事情,我建议在使用这个之前检查一下wagtail文档,因为这个项目的开发速度很快,如果他们很快提供了一种生成隐藏字段的“内置”方式,我一点也不会感到惊讶。在
  • 在我自己的测试中,我没有得到OP在评论中提到的缩进。只要结构本身是一个顶级元素,所有子元素默认都是左对齐的,因此它们与struct块之外的任何字段对齐。在
  • 当然,您可以创建基本类型的自定义块(比如自定义CharBlock),并将widget kwarg指定为forms.HiddenInput但是您仍然需要处理标签-传递一个类名kwarg只会将其应用于输入而不是标签等。使用自定义基本块意味着永远保留它们或providing deconstruct methods to avoid migration trouble。这回避了所有这些问题。在
  • 当然,任何这一切都可以通过JS/css轻松实现,但前提是我们需要一个纯html的解决方案。在

    ^{2美元

模型中的甜蜜溶液

这个答案实际上并不是问题的答案,而是在试图在后台向ImageChooser添加一些字段时使用的更好的选择。从Wagtail文档中了解到,有一种东西叫做Custom Image Model

因此,我没有尝试在Block“层”上添加字段,而是将它们添加到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或额外的模型,但这是非常老套的不赞成。在

^{pr2}$

这样,在添加额外值时就不需要额外的html, css or js。这一点是因为它占用了大量的用户体验性能,并且还重写了to_python函数和{}函数来注入额外的变量,这是非常、非常粗糙和肮脏的。但它是有效的,所以如果你不介意设计标准或性能,独自工作,别人永远也看不到你的代码,你可以用这个。在

所以不要。。在

关于你的第一个问题,为什么不只是:

class MyBlock(blocks.StructBlock):
    background = ImageChooserBlock()
    extra = blocks.Charfield()

是吗?在

相关问题 更多 >