From a266b1fe1a5a06b6861b022ad9407cfb1404d567 Mon Sep 17 00:00:00 2001 From: Dan Trickey Date: Mon, 15 Jan 2024 19:35:04 +0000 Subject: [PATCH] Add streamfield to infra page --- .../0002_use_streamfield_on_infra_index.py | 858 ++++++++++++++++++ .../0002_use_streamfield_on_infra_index.py | 210 +++++ kmicms/pages/infra/models.py | 7 +- .../infra/netbox_infrastructure_page.html | 38 +- .../0002_use_streamfield_on_infra_index.py | 204 +++++ 5 files changed, 1300 insertions(+), 17 deletions(-) create mode 100644 kmicms/pages/home/migrations/0002_use_streamfield_on_infra_index.py create mode 100644 kmicms/pages/infra/migrations/0002_use_streamfield_on_infra_index.py create mode 100644 kmicms/pages/standard_page/migrations/0002_use_streamfield_on_infra_index.py diff --git a/kmicms/pages/home/migrations/0002_use_streamfield_on_infra_index.py b/kmicms/pages/home/migrations/0002_use_streamfield_on_infra_index.py new file mode 100644 index 0000000..6b8aa80 --- /dev/null +++ b/kmicms/pages/home/migrations/0002_use_streamfield_on_infra_index.py @@ -0,0 +1,858 @@ +# Generated by Django 4.2.8 on 2024-01-15 19:28 + +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("home", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="homepage", + name="content", + field=wagtail.fields.StreamField( + [ + ( + "masthead", + wagtail.blocks.StructBlock( + [ + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + help_text="An image with dimensions 1900x1216 works best" + ), + ), + ("content", wagtail.blocks.RichTextBlock()), + ( + "cta_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ("label", wagtail.blocks.CharBlock()), + ( + "style", + wagtail.blocks.ChoiceBlock( + choices=[ + ("primary", "Primary"), + ("secondary", "Secondary"), + ("success", "Success"), + ("danger", "Danger"), + ("warning", "Warning"), + ("info", "Info"), + ("light", "Light"), + ("dark", "Dark"), + ] + ), + ), + ( + "link", + wagtail.blocks.PageChooserBlock( + label="Internal Link", + required=False, + ), + ), + ( + "external_link", + wagtail.blocks.URLBlock( + label="External Link", + required=False, + ), + ), + ] + ), + label="Call to Action buttons", + max_num=3, + ), + ), + ] + ), + ), + ( + "showcase", + wagtail.blocks.StructBlock( + [ + ( + "direction", + wagtail.blocks.ChoiceBlock( + choices=[ + ("left", "Image on Left"), + ("right", "Image on Right"), + ] + ), + ), + ("image", wagtail.images.blocks.ImageChooserBlock()), + ("title", wagtail.blocks.TextBlock()), + ("description", wagtail.blocks.TextBlock()), + ( + "cta_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ("label", wagtail.blocks.CharBlock()), + ( + "style", + wagtail.blocks.ChoiceBlock( + choices=[ + ("primary", "Primary"), + ("secondary", "Secondary"), + ("success", "Success"), + ("danger", "Danger"), + ("warning", "Warning"), + ("info", "Info"), + ("light", "Light"), + ("dark", "Dark"), + ] + ), + ), + ( + "link", + wagtail.blocks.PageChooserBlock( + label="Internal Link", + required=False, + ), + ), + ( + "external_link", + wagtail.blocks.URLBlock( + label="External Link", + required=False, + ), + ), + ] + ), + label="Call to Action buttons", + max_num=3, + ), + ), + ] + ), + ), + ( + "container", + wagtail.blocks.StructBlock( + [ + ( + "content", + wagtail.blocks.StreamBlock( + [ + ( + "heading", + wagtail.blocks.StructBlock( + [ + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ] + ), + ), + ( + "text", + wagtail.blocks.TextBlock(), + ), + ] + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(editor="all-but-headings"), + ), + ( + "alert", + wagtail.blocks.StructBlock( + [ + ( + "heading", + wagtail.blocks.CharBlock(required=False), + ), + ( + "alert_type", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "primary", + "Primary", + ), + ( + "secondary", + "Secondary", + ), + ( + "success", + "Success", + ), + ( + "danger", + "Danger", + ), + ( + "warning", + "Warning", + ), + ("info", "Info"), + ("light", "Light"), + ("dark", "Dark"), + ] + ), + ), + ( + "content", + wagtail.blocks.TextBlock(), + ), + ] + ), + ), + ( + "card_grid", + wagtail.blocks.StructBlock( + [ + ( + "grid_class", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "row-cols-md-2", + "2 Cards Wide", + ), + ( + "row-cols-md-3", + "3 Cards Wide", + ), + ( + "row-cols-md-4", + "4 Cards Wide", + ), + ], + label="Grid Type", + ), + ), + ( + "card_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "image", + wagtail.images.blocks.ImageChooserBlock(), + ), + ( + "title", + wagtail.blocks.TextBlock(), + ), + ( + "text", + wagtail.blocks.RichTextBlock(), + ), + ( + "cta_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock(), + ), + ( + "style", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "primary", + "Primary", + ), + ( + "secondary", + "Secondary", + ), + ( + "success", + "Success", + ), + ( + "danger", + "Danger", + ), + ( + "warning", + "Warning", + ), + ( + "info", + "Info", + ), + ( + "light", + "Light", + ), + ( + "dark", + "Dark", + ), + ] + ), + ), + ( + "link", + wagtail.blocks.PageChooserBlock( + label="Internal Link", + required=False, + ), + ), + ( + "external_link", + wagtail.blocks.URLBlock( + label="External Link", + required=False, + ), + ), + ] + ), + label="Calls to Action", + ), + ), + ] + ), + label="Cards", + ), + ), + ] + ), + ), + ( + "code", + wagtail.blocks.StructBlock( + [ + ( + "language", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bash", + "Bash/Shell", + ), + ("css", "CSS"), + ("diff", "diff"), + ("html", "HTML"), + ( + "javascript", + "Javascript", + ), + ("json", "JSON"), + ( + "python", + "Python", + ), + ("scss", "SCSS"), + ("yaml", "YAML"), + ], + help_text="Coding language", + identifier="language", + label="Language", + ), + ), + ( + "code", + wagtail.blocks.TextBlock( + identifier="code", + label="Code", + ), + ), + ] + ), + ), + ] + ), + ) + ] + ), + ), + ( + "columns_two", + wagtail.blocks.StructBlock( + [ + ( + "left_content", + wagtail.blocks.StreamBlock( + [ + ( + "heading", + wagtail.blocks.StructBlock( + [ + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ] + ), + ), + ( + "text", + wagtail.blocks.TextBlock(), + ), + ] + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(editor="all-but-headings"), + ), + ( + "alert", + wagtail.blocks.StructBlock( + [ + ( + "heading", + wagtail.blocks.CharBlock(required=False), + ), + ( + "alert_type", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "primary", + "Primary", + ), + ( + "secondary", + "Secondary", + ), + ( + "success", + "Success", + ), + ( + "danger", + "Danger", + ), + ( + "warning", + "Warning", + ), + ("info", "Info"), + ("light", "Light"), + ("dark", "Dark"), + ] + ), + ), + ( + "content", + wagtail.blocks.TextBlock(), + ), + ] + ), + ), + ( + "card_grid", + wagtail.blocks.StructBlock( + [ + ( + "grid_class", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "row-cols-md-2", + "2 Cards Wide", + ), + ( + "row-cols-md-3", + "3 Cards Wide", + ), + ( + "row-cols-md-4", + "4 Cards Wide", + ), + ], + label="Grid Type", + ), + ), + ( + "card_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "image", + wagtail.images.blocks.ImageChooserBlock(), + ), + ( + "title", + wagtail.blocks.TextBlock(), + ), + ( + "text", + wagtail.blocks.RichTextBlock(), + ), + ( + "cta_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock(), + ), + ( + "style", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "primary", + "Primary", + ), + ( + "secondary", + "Secondary", + ), + ( + "success", + "Success", + ), + ( + "danger", + "Danger", + ), + ( + "warning", + "Warning", + ), + ( + "info", + "Info", + ), + ( + "light", + "Light", + ), + ( + "dark", + "Dark", + ), + ] + ), + ), + ( + "link", + wagtail.blocks.PageChooserBlock( + label="Internal Link", + required=False, + ), + ), + ( + "external_link", + wagtail.blocks.URLBlock( + label="External Link", + required=False, + ), + ), + ] + ), + label="Calls to Action", + ), + ), + ] + ), + label="Cards", + ), + ), + ] + ), + ), + ( + "code", + wagtail.blocks.StructBlock( + [ + ( + "language", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bash", + "Bash/Shell", + ), + ("css", "CSS"), + ("diff", "diff"), + ("html", "HTML"), + ( + "javascript", + "Javascript", + ), + ("json", "JSON"), + ( + "python", + "Python", + ), + ("scss", "SCSS"), + ("yaml", "YAML"), + ], + help_text="Coding language", + identifier="language", + label="Language", + ), + ), + ( + "code", + wagtail.blocks.TextBlock( + identifier="code", + label="Code", + ), + ), + ] + ), + ), + ] + ), + ), + ( + "right_content", + wagtail.blocks.StreamBlock( + [ + ( + "heading", + wagtail.blocks.StructBlock( + [ + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ] + ), + ), + ( + "text", + wagtail.blocks.TextBlock(), + ), + ] + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(editor="all-but-headings"), + ), + ( + "alert", + wagtail.blocks.StructBlock( + [ + ( + "heading", + wagtail.blocks.CharBlock(required=False), + ), + ( + "alert_type", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "primary", + "Primary", + ), + ( + "secondary", + "Secondary", + ), + ( + "success", + "Success", + ), + ( + "danger", + "Danger", + ), + ( + "warning", + "Warning", + ), + ("info", "Info"), + ("light", "Light"), + ("dark", "Dark"), + ] + ), + ), + ( + "content", + wagtail.blocks.TextBlock(), + ), + ] + ), + ), + ( + "card_grid", + wagtail.blocks.StructBlock( + [ + ( + "grid_class", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "row-cols-md-2", + "2 Cards Wide", + ), + ( + "row-cols-md-3", + "3 Cards Wide", + ), + ( + "row-cols-md-4", + "4 Cards Wide", + ), + ], + label="Grid Type", + ), + ), + ( + "card_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "image", + wagtail.images.blocks.ImageChooserBlock(), + ), + ( + "title", + wagtail.blocks.TextBlock(), + ), + ( + "text", + wagtail.blocks.RichTextBlock(), + ), + ( + "cta_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock(), + ), + ( + "style", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "primary", + "Primary", + ), + ( + "secondary", + "Secondary", + ), + ( + "success", + "Success", + ), + ( + "danger", + "Danger", + ), + ( + "warning", + "Warning", + ), + ( + "info", + "Info", + ), + ( + "light", + "Light", + ), + ( + "dark", + "Dark", + ), + ] + ), + ), + ( + "link", + wagtail.blocks.PageChooserBlock( + label="Internal Link", + required=False, + ), + ), + ( + "external_link", + wagtail.blocks.URLBlock( + label="External Link", + required=False, + ), + ), + ] + ), + label="Calls to Action", + ), + ), + ] + ), + label="Cards", + ), + ), + ] + ), + ), + ( + "code", + wagtail.blocks.StructBlock( + [ + ( + "language", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bash", + "Bash/Shell", + ), + ("css", "CSS"), + ("diff", "diff"), + ("html", "HTML"), + ( + "javascript", + "Javascript", + ), + ("json", "JSON"), + ( + "python", + "Python", + ), + ("scss", "SCSS"), + ("yaml", "YAML"), + ], + help_text="Coding language", + identifier="language", + label="Language", + ), + ), + ( + "code", + wagtail.blocks.TextBlock( + identifier="code", + label="Code", + ), + ), + ] + ), + ), + ] + ), + ), + ] + ), + ), + ], + use_json_field=True, + ), + ), + ] diff --git a/kmicms/pages/infra/migrations/0002_use_streamfield_on_infra_index.py b/kmicms/pages/infra/migrations/0002_use_streamfield_on_infra_index.py new file mode 100644 index 0000000..c9e5d33 --- /dev/null +++ b/kmicms/pages/infra/migrations/0002_use_streamfield_on_infra_index.py @@ -0,0 +1,210 @@ +# Generated by Django 4.2.8 on 2024-01-15 19:28 + +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("infra", "0001_initial"), + ] + + operations = [ + migrations.RemoveField( + model_name="netboxinfrastructurepage", + name="introduction", + ), + migrations.AddField( + model_name="netboxinfrastructurepage", + name="content", + field=wagtail.fields.StreamField( + [ + ( + "heading", + wagtail.blocks.StructBlock( + [ + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ] + ), + ), + ("text", wagtail.blocks.TextBlock()), + ] + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(editor="all-but-headings"), + ), + ( + "alert", + wagtail.blocks.StructBlock( + [ + ("heading", wagtail.blocks.CharBlock(required=False)), + ( + "alert_type", + wagtail.blocks.ChoiceBlock( + choices=[ + ("primary", "Primary"), + ("secondary", "Secondary"), + ("success", "Success"), + ("danger", "Danger"), + ("warning", "Warning"), + ("info", "Info"), + ("light", "Light"), + ("dark", "Dark"), + ] + ), + ), + ("content", wagtail.blocks.TextBlock()), + ] + ), + ), + ( + "card_grid", + wagtail.blocks.StructBlock( + [ + ( + "grid_class", + wagtail.blocks.ChoiceBlock( + choices=[ + ("row-cols-md-2", "2 Cards Wide"), + ("row-cols-md-3", "3 Cards Wide"), + ("row-cols-md-4", "4 Cards Wide"), + ], + label="Grid Type", + ), + ), + ( + "card_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "image", + wagtail.images.blocks.ImageChooserBlock(), + ), + ("title", wagtail.blocks.TextBlock()), + ( + "text", + wagtail.blocks.RichTextBlock(), + ), + ( + "cta_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock(), + ), + ( + "style", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "primary", + "Primary", + ), + ( + "secondary", + "Secondary", + ), + ( + "success", + "Success", + ), + ( + "danger", + "Danger", + ), + ( + "warning", + "Warning", + ), + ( + "info", + "Info", + ), + ( + "light", + "Light", + ), + ( + "dark", + "Dark", + ), + ] + ), + ), + ( + "link", + wagtail.blocks.PageChooserBlock( + label="Internal Link", + required=False, + ), + ), + ( + "external_link", + wagtail.blocks.URLBlock( + label="External Link", + required=False, + ), + ), + ] + ), + label="Calls to Action", + ), + ), + ] + ), + label="Cards", + ), + ), + ] + ), + ), + ( + "code", + wagtail.blocks.StructBlock( + [ + ( + "language", + wagtail.blocks.ChoiceBlock( + choices=[ + ("bash", "Bash/Shell"), + ("css", "CSS"), + ("diff", "diff"), + ("html", "HTML"), + ("javascript", "Javascript"), + ("json", "JSON"), + ("python", "Python"), + ("scss", "SCSS"), + ("yaml", "YAML"), + ], + help_text="Coding language", + identifier="language", + label="Language", + ), + ), + ( + "code", + wagtail.blocks.TextBlock(identifier="code", label="Code"), + ), + ] + ), + ), + ], + default={}, + use_json_field=True, + ), + preserve_default=False, + ), + ] diff --git a/kmicms/pages/infra/models.py b/kmicms/pages/infra/models.py index 5b06c81..54d9b90 100644 --- a/kmicms/pages/infra/models.py +++ b/kmicms/pages/infra/models.py @@ -1,9 +1,10 @@ +from core.blocks import StoryBlock from django.conf import settings from django.http import Http404, HttpRequest, HttpResponse from integrations.netbox import NetboxClient, NetboxRequestError from wagtail.admin.panels import FieldPanel, TitleFieldPanel from wagtail.contrib.routable_page.models import RoutablePageMixin, path -from wagtail.fields import RichTextField +from wagtail.fields import RichTextField, StreamField from wagtail.models import Page @@ -11,13 +12,13 @@ class NetboxInfrastructurePage(RoutablePageMixin, Page): max_count = 1 subpage_types = [] - introduction = RichTextField() + content = StreamField(StoryBlock(), use_json_field=True) device_description = RichTextField() vm_description = RichTextField() content_panels = [ TitleFieldPanel("title"), - FieldPanel("introduction"), + FieldPanel("content"), FieldPanel("device_description"), FieldPanel("vm_description"), ] diff --git a/kmicms/pages/infra/templates/infra/netbox_infrastructure_page.html b/kmicms/pages/infra/templates/infra/netbox_infrastructure_page.html index 494bffe..f2fba2b 100644 --- a/kmicms/pages/infra/templates/infra/netbox_infrastructure_page.html +++ b/kmicms/pages/infra/templates/infra/netbox_infrastructure_page.html @@ -7,22 +7,32 @@

{{ page.title }}

{% include "components/breadcrumbs.html" %} -

{{ page.introduction|richtext}}

- -
-
-
Devices
-

{{ page.device_description|richtext}}

- View devices +
+
+
+
+
Devices
+

{{ page.device_description|richtext}}

+ View devices +
+
-
- -
-
-
Virtual Machines
-

{{ page.vm_description|richtext}}

- View VMs +
+
+
+
Virtual Machines
+

{{ page.vm_description|richtext}}

+ View VMs +
+
+ + {% for block in page.content %} +
+ {{ block }} +
+ {% endfor %} +
{% endblock %} \ No newline at end of file diff --git a/kmicms/pages/standard_page/migrations/0002_use_streamfield_on_infra_index.py b/kmicms/pages/standard_page/migrations/0002_use_streamfield_on_infra_index.py new file mode 100644 index 0000000..84d41b2 --- /dev/null +++ b/kmicms/pages/standard_page/migrations/0002_use_streamfield_on_infra_index.py @@ -0,0 +1,204 @@ +# Generated by Django 4.2.8 on 2024-01-15 19:28 + +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("standard_page", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="standardpage", + name="content", + field=wagtail.fields.StreamField( + [ + ( + "heading", + wagtail.blocks.StructBlock( + [ + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ] + ), + ), + ("text", wagtail.blocks.TextBlock()), + ] + ), + ), + ( + "rich_text", + wagtail.blocks.RichTextBlock(editor="all-but-headings"), + ), + ( + "alert", + wagtail.blocks.StructBlock( + [ + ("heading", wagtail.blocks.CharBlock(required=False)), + ( + "alert_type", + wagtail.blocks.ChoiceBlock( + choices=[ + ("primary", "Primary"), + ("secondary", "Secondary"), + ("success", "Success"), + ("danger", "Danger"), + ("warning", "Warning"), + ("info", "Info"), + ("light", "Light"), + ("dark", "Dark"), + ] + ), + ), + ("content", wagtail.blocks.TextBlock()), + ] + ), + ), + ( + "card_grid", + wagtail.blocks.StructBlock( + [ + ( + "grid_class", + wagtail.blocks.ChoiceBlock( + choices=[ + ("row-cols-md-2", "2 Cards Wide"), + ("row-cols-md-3", "3 Cards Wide"), + ("row-cols-md-4", "4 Cards Wide"), + ], + label="Grid Type", + ), + ), + ( + "card_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "image", + wagtail.images.blocks.ImageChooserBlock(), + ), + ("title", wagtail.blocks.TextBlock()), + ( + "text", + wagtail.blocks.RichTextBlock(), + ), + ( + "cta_list", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock(), + ), + ( + "style", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "primary", + "Primary", + ), + ( + "secondary", + "Secondary", + ), + ( + "success", + "Success", + ), + ( + "danger", + "Danger", + ), + ( + "warning", + "Warning", + ), + ( + "info", + "Info", + ), + ( + "light", + "Light", + ), + ( + "dark", + "Dark", + ), + ] + ), + ), + ( + "link", + wagtail.blocks.PageChooserBlock( + label="Internal Link", + required=False, + ), + ), + ( + "external_link", + wagtail.blocks.URLBlock( + label="External Link", + required=False, + ), + ), + ] + ), + label="Calls to Action", + ), + ), + ] + ), + label="Cards", + ), + ), + ] + ), + ), + ( + "code", + wagtail.blocks.StructBlock( + [ + ( + "language", + wagtail.blocks.ChoiceBlock( + choices=[ + ("bash", "Bash/Shell"), + ("css", "CSS"), + ("diff", "diff"), + ("html", "HTML"), + ("javascript", "Javascript"), + ("json", "JSON"), + ("python", "Python"), + ("scss", "SCSS"), + ("yaml", "YAML"), + ], + help_text="Coding language", + identifier="language", + label="Language", + ), + ), + ( + "code", + wagtail.blocks.TextBlock(identifier="code", label="Code"), + ), + ] + ), + ), + ], + use_json_field=True, + ), + ), + ]