diff --git a/example/db.sqlite3 b/example/db.sqlite3 index af6892eb..aaa854ff 100644 Binary files a/example/db.sqlite3 and b/example/db.sqlite3 differ diff --git a/example/example/settings/base.py b/example/example/settings/base.py index dee59f63..71c91c9b 100644 --- a/example/example/settings/base.py +++ b/example/example/settings/base.py @@ -56,6 +56,7 @@ # GRAPPLE SPECIFIC MODULES "grapple", "graphene_django", + "django_extensions", ] MIDDLEWARE = [ @@ -191,3 +192,8 @@ } except ImportError: pass + + +# Query Optimization helpers +SHELL_PLUS_PRINT_SQL = True +RUNSERVER_PLUS_PRINT_SQL_TRUNCATE = 100000 diff --git a/example/home/migrations/0019_auto_20201124_2247.py b/example/home/migrations/0019_auto_20201124_2247.py new file mode 100644 index 00000000..18e5ad14 --- /dev/null +++ b/example/home/migrations/0019_auto_20201124_2247.py @@ -0,0 +1,26 @@ +# Generated by Django 3.1.3 on 2020-11-24 22:47 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("images", "0001_initial"), + ("home", "0018_add_pagechooserblock"), + ] + + operations = [ + migrations.AlterField( + model_name="blogpage", + name="cover", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="images.customimage", + ), + ), + ] diff --git a/example/home/models.py b/example/home/models.py index ae85ed58..77b16a01 100644 --- a/example/home/models.py +++ b/example/home/models.py @@ -70,7 +70,7 @@ class BlogPage(HeadlessPreviewMixin, Page): related_name="+", ) cover = models.ForeignKey( - "wagtailimages.Image", + "images.CustomImage", null=True, blank=True, on_delete=models.SET_NULL, diff --git a/grapple/apps.py b/grapple/apps.py index 43565796..f05b7ef5 100644 --- a/grapple/apps.py +++ b/grapple/apps.py @@ -12,6 +12,14 @@ def ready(self): from .actions import import_apps, load_type_fields from .types.streamfield import register_streamfield_blocks + self.preload_tasks() import_apps() load_type_fields() register_streamfield_blocks() + + def preload_tasks(self): + # Monkeypatch Wagtails' PageQueryset .specific method to a more optimized one + from wagtail.core.query import PageQuerySet + from .db.query import specific + + PageQuerySet.specific = specific diff --git a/grapple/db/__init__.py b/grapple/db/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/grapple/db/optimizer.py b/grapple/db/optimizer.py new file mode 100644 index 00000000..baf2af24 --- /dev/null +++ b/grapple/db/optimizer.py @@ -0,0 +1,256 @@ +import re +from django.db.models.fields.related_descriptors import ( + ReverseOneToOneDescriptor, + ReverseOneToOneDescriptor, +) +from graphene.types.definitions import GrapheneInterfaceType +from graphql.language.ast import Field, InlineFragment, FragmentSpread + +from modelcluster.fields import ParentalKey + +pascal_to_snake = re.compile(r"(?