torchbox / wagtail-grapple

A Wagtail app that makes building GraphQL endpoints a breeze!
https://wagtail-grapple.readthedocs.io/en/latest/
Other
151 stars 57 forks source link

Wagtail 4.1.1 compatibility for Snippets #307

Open dopry opened 1 year ago

dopry commented 1 year ago

I just ran into an issue with https://github.com/wagtail/wagtail/pull/9605

I have a field definition like

categories = graphene.List(SnippetTypes.get_object_type())

My graphql interface started spitting out the error

lib\site-packages\graphene\types\schema.py", line 122, in add_type
    name = graphene_type._meta.name
AttributeError: 'NoneType' object has no attribute '_meta'

I don't import my grapple type definitions until my app.ready(), but I guess that is running before snippets.app.ready because get_object type() now returns None since snippets are not registered yet.

I am able to make it work by moving graphene_django, grapple, and my app after wagtail.snippets... This obviously isn't very ideal since now the template priority favors wagtail over my apps... :(

zerolab commented 1 year ago

Any chance you could add a minimal reproducible code snippet (or snippets)?

I don't have a good answer for this yet as we are always at the mercy of app interdependency.

dopry commented 1 year ago

I would be something along the lines of

settings.py

INSTALLED_APPS = [
    # graphql to make it all headless
    "graphene_django",
    "grapple",
    "myapp",

    # core wagtail stuff
    "wagtail.contrib.forms",
    "wagtail.contrib.redirects",
    "wagtail.embeds",
    "wagtail.sites",
    "wagtail.users",
    "wagtail.snippets",
    "wagtail.documents",
    "wagtail.images",
    "wagtail.search",
    "wagtail.admin",
    "wagtail",

app.py


@register_snippet
class PageCategory(Model):
    name = CharField(max_length=255)
    slug = CharField(max_length=255, unique=True)
    panels = [ FieldPanel("name"),    FieldPanel("slug")   ]

    def __str__(self):
        return self.name

    graphql_fields = [  GraphQLString("name"),    GraphQLString("slug"), ]

class MySnippetBlock(StructBlock):
    categories = ListBlock(SnippetChooserBlock("myapp.Category", required=False))

class MyPage(Page): 
    body = StreamField([MySnippetBlock])

class MyApp(AppConfig):
    name = "MyApp"

    def ready(self):

        class MySnippetType: 
              from grapple.types.snippets import SnippetTypes
              snippet_relationship = graphene.List(SnippetTypes.get_object_type())

The gist is registry.snippets.types is empty when SnippetTypes.get_object_type() is called.

I can work on a more formal test setup next week if it's necessary, but I'm launching a new property this week. This was just something I ran into trying to get on latest wagtail before launch, but isn't critical.

dopry commented 5 months ago

@zerolab this hit me again today as I was trying to upgrade my wagtail instance. I figured I should get on 5 before 6 gets releases. I don't want to be too far behind the current. ultimately what I had to do to resolve this was move my grapple implementation to it's own app and move grapple and my graphql app to after wagtail core... I ended up with

INSTALLED_APPS = [
    # graphql to make it all headless
    "graphene_django",
    "myapp",

    # core wagtail stuff
    "wagtail.contrib.forms",
    "wagtail.contrib.redirects",
    "wagtail.embeds",
    "wagtail.sites",
    "wagtail.users",
    "wagtail.snippets",
    "wagtail.documents",
    "wagtail.images",
    "wagtail.search",
    "wagtail.admin",
    "wagtail",

    "grapple",
    "myapp_grapple"

if the setup documentation isn't explicit about making the grapple integration it's own app and grapple's location in installed apps relative to wagtail that seems like it might be something worth doing to help other users avoid the headache I just went through working that out.