2017-10-13 6 views
0

Existe-t-il un meilleur moyen de faire une sous-classe de ListBlock avec un contenu fixe?Comment définir une sous-classe de ListBlock avec un contenu fixe?

class MixedMediaCarouselBlock(blocks.ListBlock): 
    """ 
    A hghly streamlined CarouselBlock which displays only Images and/or Videos. 
    """ 

    def __init__(self, child_block=None, **kwargs): 
     child_block = blocks.StructBlock([ 
      ('image', ImageChooserBlock(required=False)), 
      ('video', EmbedBlock(
       label="Video URL", 
       help_text="Paste the video URL from YouTube or Vimeo." 
          " e.g. https://www.youtube.com/watch?v=l3Pz_xQZVDg" 
          " or https://vimeo.com/207076450.", 
       required=False 
       ) 
      ), 
     ]) 
     super(MixedMediaCarouselBlock, self).__init__(child_block, **kwargs) 

    class Meta: 
     template = 'core/blocks/mixed_media_carousel_block.html' 
     label = 'Mixed Media Carousel' 
     icon = 'media' 

Il se sent vraiment aki de le faire de cette façon, mais je ne peux trouver aucune autre méthode évidente, car ListBlock exige que l'argument child_block à son constructeur, tandis que d'autres types de blocs ne le font pas.

La raison pour laquelle je veux une sous-classe ListBlock est de l'utiliser comme type de bloc unique dans un StreamField dans l'une de mes pages:

class News(Page) 
    assets = StreamField(
     MixedMediaCarouselBlock(), 
     help_text='Pick one or more images/videos to place in the sidebar of this article.' 
    ) 

Peut-être que je vais juste faire ce mal?

EDIT: Ouais, je suis définitivement en train de faire quelque chose de mal. Cela ne fonctionne pas du tout, comme je viens de le découvrir quand j'ai essayé d'enregistrer une page avec cette configuration et j'ai obtenu AttributeError: 'MixedMediaCarouselBlock' object has no attribute 'child_blocks' sur wagtail/wagtailcore/blocks/stream_block.py ligne 401. (Wagtail 1.12.2). Aucune idée pourquoi, cependant.

EDIT2: J'ai suivi @ conseils de Gasman, et est venu avec ceci:

class MixedMediaCarouselBlock(blocks.StreamBlock): 
    slides = blocks.ListBlock(
     blocks.StructBlock([ 
      ('image', ImageChooserBlock(required=False)), 
      ('video', EmbedBlock(
       label="Video URL", 
       help_text="Paste the video URL from YouTube or Vimeo." 
          " e.g. https://www.youtube.com/watch?v=l3Pz_xQZVDg or https://vimeo.com/207076450.", 
       required=False 
       ) 
      ), 
     ]) 
    ) 

Mais je reçois toujours un menu de type de bloc sur le formulaire de modification de la page (j'utilise Bergeronnette-lifting):

Block Type Menu

Pire encore, la forme me permet d'ajouter plusieurs instances de slides au Streamfield, qui pourrait facilement conduire à des utilisateurs faisant accidentellement plusieurs mono-éléments ListBlocks, au lieu d'un multi-éléments ListBlock, qui br fonce le moteur de rendu. Que puis-je faire à ce sujet?

EDIT3: C'est ce que j'ai trouvé après beaucoup d'expérimentation, mais je ne l'aime pas du tout.

class MixedMediaCarouselBlock(blocks.StructBlock): 
    """ 
    A hghly streamlined CarouselBlock which displays only Images and/or Videos. 
    """ 

    slides = blocks.ListBlock(
     blocks.StructBlock([ 
      ('image', ImageChooserBlock(required=False)), 
      ('video', EmbedBlock(
       label="Video URL", 
       help_text="Paste the video URL from YouTube or Vimeo." 
          " e.g. https://www.youtube.com/watch?v=l3Pz_xQZVDg or https://vimeo.com/207076450.", 
       required=False 
       ) 
      ), 
     ]) 
    ) 

    class Meta: 
     template = 'core/blocks/mixed_media_carousel_block.html' 
     label = 'Mixed Media Carousel' 
     icon = 'media' 

class News(Page): 
    ... 
    assets = StreamField(
     ('media', MixedMediaCarouselBlock()), 
     help_text='Pick one or more images/videos to place in the sidebar of this article.' 
    ) 

Ensuite, pour gérer le problème des utilisateurs d'ajouter accidentellement plusieurs MixedMediaCarouselBlock s au lieu de plusieurs vidéos/images dans un seul MixedMediaCarouselBlock, je piraté un peu de MOINS CSS pour cacher l'interface utilisateur qui leur permettrait de le faire:

body.model-news { 
    .stream-menu .toggle { 
    display: none; 
    } 

    .sequence-controls:not(.list-controls) button[id$=delete] { 
    display: none; 
    } 
} 

au cours de ma R & D, je courais à travers les notes de patch Bergeronnette 1.12, qui mentionnent l'ajout des min_num, max_num et block_counts méta attrs à StreamBlock, qui semblait vraiment prometteur. Mais ils n'affectent pas l'interface utilisateur; ils ajoutent simplement une validation côté serveur qui fait apparaître des choix invalides sous la forme d'erreurs de formulaire après POSTing. Si elles empêchaient d'abord de faire des changements non valables, je pourrais effectivement les utiliser.

Répondre

1

Votre définition de bloc est correcte, autant que je peux voir. ListBlock n'a pas été conçu pour être sous-classé, donc essayer de le faire est inévitablement un peu hacky et pas garanti pour être stable à travers les versions de Wagtail - mais vous ne comptez pas sur les internes de ListBlock, seulement en modifiant le constructeur signature de la méthode, il devrait donc être assez sûr. Gardez à l'esprit que si vous sousclassez un bloc autre que StructBlock, StreamBlock ou ChoiceBlock, les références à votre sous-classe apparaîtront dans les fichiers de migration, et il est de votre responsabilité de conserver la définition de classe tant que ces migrations existent: http://docs.wagtail.io/en/v1.12.2/topics/streamfield.html#streamfield-definitions-within-migrations.Le problème ici est que StreamBlock (et les sous-classes) est actuellement le seul type de bloc autorisé comme bloc de premier niveau d'un StreamField: autoriser d'autres types de blocs a été proposé (#2048) mais n'a pas encore été implémenté. Pour contourner ce problème, vous pouvez définir MixedMediaCarouselBlock en tant que StreamBlock avec un seul type de bloc enfant; ce n'est pas aussi maladroit que cela puisse paraître, car dans cette situation, le menu pour choisir un type de bloc est ignoré (#1696), ce qui rend le comportement plus ou moins identique à un ListBlock.

+0

Merci pour l'explication! Même si je ne comprends pas très bien le comportement que vous avez décrit. Peut-être que j'ai conçu ma mise à jour 'MixedMediaCarouselBlock' mal? Je l'ai ajouté, et le problème que j'ai toujours, à la question originale. – CoreDumpError

+0

L'idée d'utiliser StreamBlock est que vous feriez du StructBlock le seul et unique enfant, et que vous omettiez le calque ListBlock. Je vais devoir me familiariser avec le fonctionnement des StreamBlocks mono-enfant, puis - je pense qu'il se peut que le menu apparaisse sur l'état vide initial, mais pas lors d'un clic ultérieur sur le bouton 'ajouter'. – gasman

+0

Eh bien, cela fonctionnerait ... mais l'interface utilisateur pour "ajouter un bloc" est nettement moins jolie que l'interface utilisateur pour "ajouter un autre élément' ListBlock' ". Mais cela peut être la meilleure solution, étant donné que ListBlock n'est pas utilisable comme bloc de haut niveau. Si vous voulez, consultez mon "EDIT3". J'ai trouvé un moyen de faire ce travail, mais c'est assez hacky que je puisse aller avec votre solution à la place. – CoreDumpError