wagtail / wagtail-generic-chooser

A toolkit for custom chooser popups in Wagtail
BSD 3-Clause "New" or "Revised" License
116 stars 25 forks source link

Missing minimum docs for multiple select feature #71

Open pySilver opened 1 year ago

pySilver commented 1 year ago

I've tried to find out how "select multiple" is supposed to work but I've failed and I had to give up. It would be really nice to have a minimal example that shows how to implement a custom chooser for m2m relation.

I've tried to use it this way:

class BlogCategoryChooser(AdminChooser):
    choose_one_text = _("Choose a blog category")
    choose_another_text = _("Choose another blog category")
    link_to_chosen_text = _("Edit this blog category")
    # choose_modal_url_name = "blog_category_chooser:choose"
    icon = "user"

    choose_modal_url_name = "blog_category_chooser:chosen_multiple"

    @property
    def model(self):
        return BlogCategory

class EntryPage(Page):
    ...
    categories = ParentalManyToManyField("blogs.BlogCategory", blank=True)
    content_panels = [
      FieldPanel("categories", widget=BlogCategoryChooser),
   ]

and this resulted into the following exception

Environment:

Request Method: GET
Request URL: http://localhost:8000/cms/pages/add/blogs/entrypage/69876/

Django Version: 4.1.9
Python Version: 3.9.16
Installed Applications:
['whitenoise.runserver_nostatic',
 'django.contrib.auth',
 'django.contrib.admin',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.postgres',
 'django.contrib.humanize',
 'django.forms',
 'dal',
 'dal_select2',
 'django_admin_hstore_widget',
 'django_celery_beat',
 'django_elasticsearch_dsl',
 'django_filters',
 'django_extensions',
 'django_countries',
 'cacheback',
 'honeypot',
 'crispy_forms',
 'psqlextra',
 'django_jinja',
 'allauth',
 'allauth.account',
 'allauth.socialaccount',
 'rest_framework',
 'wagtail.contrib.forms',
 'wagtail.contrib.modeladmin',
 'wagtail.contrib.routable_page',
 'wagtail.contrib.settings',
 'wagtail.contrib.table_block',
 'wagtail.contrib.redirects',
 'wagtail.embeds',
 'wagtail.sites',
 'wagtail.users',
 'wagtail.snippets',
 'wagtail.documents',
 'wagtail.images',
 'wagtail.search',
 'wagtail.admin',
 'wagtail',
 'modelcluster',
 'taggit',
 'treebeard',
 'captcha',
 'meta',
 'mathfilters',
 'djmoney',
 'generic_chooser',
 'django_pickling',
 'cachalot',
 'myproject.core.apps.CoreConfig',
 'myproject.ad_integrations.apps.AdIntegrationsConfig',
 'myproject.affiliates.apps.AffiliatesConfig',
 'myproject.users.apps.UsersConfig',
 'myproject.legacy.apps.LegacyConfig',
 'myproject.banners.apps.BannersConfig',
 'myproject.home.apps.HomeConfig',
 'myproject.pages.apps.PagesConfig',
 'myproject.menus.apps.MenusConfig',
 'myproject.search_terms.apps.SearchTermsConfig',
 'myproject.contact.apps.ContactConfig',
 'myproject.brands.apps.BrandsConfig',
 'myproject.merchants.apps.MerchantsConfig',
 'myproject.catalog.apps.CatalogConfig',
 'myproject.wishlists.apps.WishlistsConfig',
 'myproject.coupons.apps.CouponsConfig',
 'myproject.blogs.apps.BlogConfig',
 'myproject.sitemaps.apps.SitemapsConfig',
 'wagtail.contrib.styleguide']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'whitenoise.middleware.WhiteNoiseMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.locale.LocaleMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django_structlog.middlewares.RequestMiddleware',
 'django_structlog.middlewares.CeleryMiddleware',
 'pyinstrument.middleware.ProfilerMiddleware',
 'myproject.core.middleware.SiteMiddleware',
 'myproject.catalog.middleware.RedirectMiddleware',
 'wagtail.contrib.redirects.middleware.RedirectMiddleware']

Template error:
In template /opt/venv/lib/python3.9/site-packages/wagtail/admin/templates/wagtailadmin/panels/object_list.html, error at line 9
   Field 'id' expected a number but got [].
   1 : {% load wagtailadmin_tags %}
   2 : 
   3 : <div class="w-form-width">
   4 :     {% if self.help_text %}
   5 :         {% help_block status="info" %}{{ self.help_text }}{% endhelp_block %}
   6 :     {% endif %}
   7 :     {% for child, identifier in self.visible_children_with_identifiers %}
   8 :         {% panel id_prefix=self.prefix id=identifier classname=child.classes|join:' ' heading=child.heading heading_size="label" icon=child.icon id_for_label=child.id_for_label is_required=child.is_required %}
   9 :              {% component child %} 
   10 :         {% endpanel %}
   11 :     {% endfor %}
   12 : </div>
   13 : 

Traceback (most recent call last):
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/fields/__init__.py", line 2018, in get_prep_value
    return int(value)

The above exception (int() argument must be a string, a bytes-like object or a number, not 'list') was the direct cause of the following exception:
  File "/opt/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 56, in inner
    response = get_response(request)
  File "/opt/venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 220, in _get_response
    response = response.render()
  File "/opt/venv/lib/python3.9/site-packages/wagtail/admin/auth.py", line 203, in overridden_render
    return render()
  File "/opt/venv/lib/python3.9/site-packages/django/template/response.py", line 114, in render
    self.content = self.rendered_content
  File "/opt/venv/lib/python3.9/site-packages/django/template/response.py", line 92, in rendered_content
    return template.render(context, self._request)
  File "/opt/venv/lib/python3.9/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/loader_tags.py", line 157, in render
    return compiled_parent._render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/loader_tags.py", line 157, in render
    return compiled_parent._render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/loader_tags.py", line 157, in render
    return compiled_parent._render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/loader_tags.py", line 63, in render
    result = block.nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/loader_tags.py", line 63, in render
    result = block.nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1064, in render
    output = self.filter_expression.resolve(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 715, in resolve
    obj = self.var.resolve(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 847, in resolve
    value = self._resolve_lookup(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 914, in _resolve_lookup
    current = current()
  File "/opt/venv/lib/python3.9/site-packages/wagtail/admin/panels/base.py", line 284, in render_form_content
    return mark_safe(self.render_html() + self.render_missing_fields())
  File "/opt/venv/lib/python3.9/site-packages/wagtail/admin/ui/components.py", line 20, in render_html
    return template.render(context_data)
  File "/opt/venv/lib/python3.9/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/defaulttags.py", line 238, in render
    nodelist.append(node.render_annotated(context))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/defaulttags.py", line 321, in render
    return nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1064, in render
    output = self.filter_expression.resolve(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 715, in resolve
    obj = self.var.resolve(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 847, in resolve
    value = self._resolve_lookup(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 914, in _resolve_lookup
    current = current()
  File "/opt/venv/lib/python3.9/site-packages/wagtail/admin/ui/components.py", line 20, in render_html
    return template.render(context_data)
  File "/opt/venv/lib/python3.9/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/defaulttags.py", line 238, in render
    nodelist.append(node.render_annotated(context))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/wagtail/admin/templatetags/wagtailadmin_tags.py", line 1155, in render
    children = self.nodelist.render(context) if self.nodelist else ""
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/venv/lib/python3.9/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/venv/lib/python3.9/site-packages/django/template/library.py", line 237, in render
    output = self.func(*resolved_args, **resolved_kwargs)
  File "/opt/venv/lib/python3.9/site-packages/wagtail/admin/templatetags/wagtailadmin_tags.py", line 1083, in component
    return obj.render_html(context)
  File "/opt/venv/lib/python3.9/site-packages/wagtail/admin/ui/components.py", line 15, in render_html
    context_data = self.get_context_data(parent_context)
  File "/opt/venv/lib/python3.9/site-packages/wagtail/admin/panels/field_panel.py", line 247, in get_context_data
    rendered_field = self.bound_field.as_widget(attrs=widget_attrs)
  File "/opt/venv/lib/python3.9/site-packages/django/forms/boundfield.py", line 99, in as_widget
    return widget.render(
  File "/opt/venv/lib/python3.9/site-packages/wagtail/utils/widgets.py", line 28, in render
    value_data = self.get_value_data(value)
  File "/opt/venv/lib/python3.9/site-packages/generic_chooser/widgets.py", line 124, in get_value_data
    instance = self.get_instance(value)
  File "/opt/venv/lib/python3.9/site-packages/generic_chooser/widgets.py", line 79, in get_instance
    return self.model.objects.get(pk=value)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/query.py", line 636, in get
    clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/query.py", line 1421, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/query.py", line 1439, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/query.py", line 1446, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1532, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1562, in _add_q
    child_clause, needed_inner = self.build_filter(
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1478, in build_filter
    condition = self.build_lookup(lookups, col, value)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1303, in build_lookup
    lookup = lookup_class(lhs, rhs)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/lookups.py", line 27, in __init__
    self.rhs = self.get_prep_lookup()
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/lookups.py", line 341, in get_prep_lookup
    return super().get_prep_lookup()
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/lookups.py", line 85, in get_prep_lookup
    return self.lhs.output_field.get_prep_value(self.rhs)
  File "/opt/venv/lib/python3.9/site-packages/django/db/models/fields/__init__.py", line 2020, in get_prep_value
    raise e.__class__(

Exception Type: TypeError at /cms/pages/add/blogs/entrypage/69876/
Exception Value: Field 'id' expected a number but got [].

Am I missing something?