StreamField: How to create custom ForeignKey Blocks?

2,698 views
Skip to first unread message

Sondre Lefsaker

unread,
Jul 15, 2015, 5:24:40 AM7/15/15
to wag...@googlegroups.com
I want to extend a streamfield with a PersonBlock.
The UserBlock should consist of fields like name, email, an image and so on.

I'm thinking that the easiest thing would be to use the django.contrib.auth User, so a PersonBlock should look something like this:
class PersonBlock(StructBlock):
    user
= models.ForeignKey(
       
User,
       
null=True,
        blank
=False,
        on_delete
=models.SET_NULL,
        related_name
='+',
   
)
    image
= ImageChooserBlock(required=False)

This will not work because the use 'user' field is not a FieldBlock, so my question is:

Is there an easy way to create a chooser-field (a wagtailadmin.widgets.AdminChooser maybe?) for arbitrary database models like this?
Would this require me to define a new custom 'UserChooser' class and a template to runder it, or is there another straight-forward way to do this?

I'm still very new to wagtail, so I would prefer to stay away from extending the wagtailadmin interface if that's possible :)

Thanks!

Matthew Westcott

unread,
Jul 15, 2015, 8:06:58 AM7/15/15
to wag...@googlegroups.com
Hi Sondre,

Creating new popup AdminChooser interfaces for new models requires some heavy hacking on wagtailadmin at the moment (this is something we're hoping to improve in future releases) - but if you're happy with a simple select box, you can set it up by defining a block type like this:


from wagtail.wagtailcore import blocks
from django import forms
from django.contrib.auth.models import User

class UserChooserBlock(blocks.ChooserBlock):
target_model = User
widget = forms.Select


Then use UserChooserBlock(required=False) as the 'user' field of your PersonBlock.

Cheers,
- Matt
> --
> You received this message because you are subscribed to the Google Groups "Wagtail support" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to wagtail+u...@googlegroups.com.
> To post to this group, send email to wag...@googlegroups.com.
> Visit this group at http://groups.google.com/group/wagtail.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/wagtail/fd0184ef-45d4-470e-8f16-837d6bb361b9%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Sondre Lefsaker

unread,
Jul 15, 2015, 8:52:23 AM7/15/15
to wag...@googlegroups.com
Although a kind of AdminChooser would be (and look) nice, a simple select box like this does the job!

Thank you Matt!

David Prothero

unread,
Apr 14, 2016, 4:55:12 PM4/14/16
to Wagtail support
Hey Matt, I tried this and it appeared to work, however, when I reload the page, the select inputs don't have the value selected anymore. I can see the pk's are stored in the JSON for the StreamField, but it's just not re-selecting the previously selected choice.

class TagChooserBlock(blocks.ChooserBlock):
    target_model = Tag
    widget = forms.Select 


class TutorialCategoryBlock(blocks.StructBlock):
    tag = TagChooserBlock(required=True)
    heading = blocks.CharBlock(required=True)
    left_nav = blocks.BooleanBlock(required=False, default=True, 
        help_text='Whether to show in left navigation.')


class TutorialIndexPage(TwilioDocsMixin, Page):
    """A page type for the Tutorial index"""

    body = StreamField([
        ('rich_text', blocks.RichTextBlock(icon='edit')),
        ('markdown', blocks.TextBlock(icon='form', template='core/markdown.html')),
        ('category', TutorialCategoryBlock(icon='folder'))
    ])


That target model of Tag is from taggit.models.

Any thoughts? Thanks!

David

David Prothero

unread,
Apr 15, 2016, 6:01:24 PM4/15/16
to Wagtail support
I was able to fix it by overriding value_for_form() in my ChooserBlock:

class TagChooserBlock(blocks.ChooserBlock):
    target_model = Tag
    widget = forms.Select 

    # 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



Thanks.

David
Reply all
Reply to author
Forward
0 new messages