Wagtail, how do I populate the choices in a ChoiceBlock from a different model?
Asked Answered
P

1

8

This is the model for icons displayed on top of a text, they get a name and the icon.

from django.db import models
from django.utils.translation import ugettext as _
from django.conf import settings


class SomeSortOfIcon(models.Model):

    name = models.CharField(max_length=200,
                            verbose_name=_('Icon Name'),
                            help_text=_('This value will be shown to the user.'))

    image = models.ForeignKey(
        getattr(settings, 'WAGTAILIMAGES_IMAGE_MODEL', 'wagtailimages.Image'),
        on_delete=models.PROTECT,
        related_name='+',
        verbose_name=_('Icon'),
    )

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = _('Icon')
        verbose_name_plural = _('Icons')

This is the code for the Block that's going to be added into a streamfield onto the page.

from django.db import models
from django import forms
from django.utils.translation import ugettext as _

from wagtail.wagtailcore import blocks

from xxx.models import SomeSortOfIcon


class SomeSortOfIconChooserBlock(blocks.ChoiceBlock):
    ## PROBLEM HERE, where do I get the choices from?
    choices = tuple([(element.name, element.image) for element in SomeSortOfIcon.objects.all()])
    target_model = SomeSortOfIcon


class SomeBox(blocks.StructBlock):

    headline = blocks.TextBlock(required=True)

    some_icon = SomeSortOfIconChooserBlock(label='Icon', required=True)

    info_box_content = blocks.RichTextBlock(label='Content', required=True)

    class Meta:
        template = 'blocks/some_box.html'
        icon = 'form'
        label = _('Some Box')

So, I do get the Block added to the streamfield and for the icon I want a dropdown menu with the choices from the icon model. It's supposed to display the name and when you chose one it is going to be automatically added by name into the html.

I get the dropdown menu, but it is empty. I tried to use the choices attribute, but I don't know how to connect it to the other model.

Can anyone please help? It'd be much appreciated.

Puree answered 2/8, 2016 at 13:42 Comment(0)
R
11

You can do that by inheriting from the ChooserBlock.

class SomeSortOfIconChooserBlock(blocks.ChooserBlock):
    target_model = SomeSortOfIcon
    widget = forms.Select

    class Meta:
        icon = "icon"

    # Return the key value for the select field
    def value_for_form(self, value):
        if isinstance(value, self.target_model):
            return value.pk
        else:
            return value

and in your block just use

class SomeBox(blocks.StructBlock):
    headline = blocks.TextBlock(required=True)
    some_icon = SomeSortOfIconChooserBlock(required=True)
    info_box_content = blocks.RichTextBlock(label='Content', required=True)

    class Meta:
        template = 'blocks/some_box.html'
        icon = 'form'
        label = _('Some Box')

This will give you a drop down based on the objects of the SomeSortOfIcon model.

Rowen answered 15/8, 2016 at 6:16 Comment(1)
This works but is throwing an error "invalid literal for int() with base 10: '' " when no option is selected.Fragrant

© 2022 - 2024 — McMap. All rights reserved.