Stephen

Thank you. I should have remembered to return super()! That has stopped it barfing and I'll withdraw my earlier question.

I'm still researching because  kwargs["widget"] = CommonFilteredSelectMultiple doesn't seem to switch the field away from FilteredSelectMultiple. At this point anyway.

Thanks again

Mike


On 6/01/2020 4:55 pm, Stephen J. Butler wrote:
Take another look at the doc's example on formfield_for_manytomany:

https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_manytomany

You need to call super() and this isn't the right way to override the widget.

def formfield_for_manytomany(self, db_field, request, **kwargs):
        if db_field.name <http://db_field.name> == "groups":
            kwargs["widget"] = CommonFilteredSelectMultiple
        return super().formfield_for_manytomany(db_field, request, **kwargs)

On Sun, Jan 5, 2020 at 11:05 PM Mike Dewhirst <mi...@dewhirst.com.au <mailto:mi...@dewhirst.com.au>> wrote:

    Significant refinement of the error ...

    Trying to use formfield_for_manytomany() triggers the error even
    if all
    it does is "pass"

    Something fishy ... I'll write a fresh question.

    Mike

    On 6/01/2020 12:46 pm, Mike Dewhirst wrote:
    > This error occurs in the Admin for my custom user when I try to
    > specify a custom widget for permission groups. I haven't included
    > 'groups' in any raw_id_fields, radio_fields or autocomplete_fields.
    > The groups are correctly displayed in the Admin user page with the
    > default FilteredSelectMultiple widget.
    >
    > This is the relevant code in admin.py ... (traceback below)
    >
    > class CommonUserAdmin(UserAdmin):
    >
    >     model = get_user_model()
    >
    >     def formfield_for_manytomany(self, db_field, request, **kwargs):
    >
    >         if db_field.name <http://db_field.name> == "groups":
    >             formfield_overrides = {
    >                 models.ManyToManyField: {'widget':
    > CommonFilteredSelectMultiple},
    >             }
    >     ...
    >
    > If I omit the formfield_for_manytomany() method and just run
    > formfield_overrides nakedly nothing happens - presumably because
    the
    > admin doesn't consider "groups" is a ManyToManyField at that point.
    >
    > How do I persuade the Admin to use my widget?
    >
    > Thanks for any advice
    >
    > Mike
    >
    >
    >
    > Environment:
    >
    >
    > Request Method: GET
    > Request URL: http://localhost:8000/admin/common/user/59/change/
    >
    > Django Version: 2.2.9
    > Python Version: 3.7.4
    > Installed Applications:
    > ['django.contrib.auth',
    >  'django.contrib.contenttypes',
    >  'django.contrib.sessions',
    >  'django.contrib.sites',
    >  'django.contrib.messages',
    >  'django.contrib.admin',
    >  'django.contrib.admindocs',
    >  'django.contrib.staticfiles',
    >  'common',
    >  'billing',
    >  'company',
    >  'credit',
    >  'refer',
    >  'regulation',
    >  'substance',
    >  'workplace']
    > Installed Middleware:
    > ['django.middleware.cache.UpdateCacheMiddleware',
    >  'django.middleware.security.SecurityMiddleware',
    >  '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.contrib.admindocs.middleware.XViewMiddleware',
    >  'django.middleware.clickjacking.XFrameOptionsMiddleware',
    >  'pwned_passwords_django.middleware.PwnedPasswordsMiddleware',
    >  'django.middleware.cache.FetchFromCacheMiddleware']
    >
    >
    > Template error:
    > In template
    >
    
D:\Users\mike\envs\xxex3\lib\site-packages\django\contrib\admin\templates\admin\includes\fieldset.html,

    > error at line 7
    >    Key 'groups' not found in 'UserForm'. Choices are: email,
    > first_name, is_active, is_staff, last_name, password, username.
    >    1 : <fieldset class="module aligned {{ fieldset.classes }}">
    >    2 :     {% if fieldset.name <http://fieldset.name> %}<h2>{{
    fieldset.name <http://fieldset.name> }}</h2>{% endif %}
    >    3 :     {% if fieldset.description %}
    >    4 :         <div class="description">{{
    fieldset.description|safe
    > }}</div>
    >    5 :     {% endif %}
    >    6 :     {% for line in fieldset %}
    >    7 :         <div class="form-row{% if
    line.fields|length_is:'1' and
    > line.errors %} errors{% endif %}{% if not line.has_visible_field %}
    > hidden{% endif %} {% for field in line %} {% if field.field.name
    <http://field.field.name> %}
    > field-{{ field.field.name <http://field.field.name> }}{% endif
    %}{% endfor %}">
    >    8 :             {% if line.fields|length_is:'1' %}{{ line.errors
    > }}{% endif %}
    >    9 :             {% for field in line %}
    >    10 :                 <div{% if not line.fields|length_is:'1' %}
    > class="fieldBox{% if field.field.name <http://field.field.name>
    %} field-{{ field.field.name <http://field.field.name>
    > }}{% endif %}{% if not field.is_readonly and field.errors %}
    errors{%
    > endif %}{% if field.field.is_hidden %} hidden{% endif %}"{% elif
    > field.is_checkbox %} class="checkbox-row"{% endif %}>
    >    11 :                     {% if not line.fields|length_is:'1' and
    > not field.is_readonly %}{{ field.errors }}{% endif %}
    >    12 :                     {% if field.is_checkbox %}
    >    13 :                         {{ field.field }}{{
    field.label_tag }}
    >    14 :                     {% else %}
    >    15 :                         {{ field.label_tag }}
    >    16 :                         {% if field.is_readonly %}
    >    17 :                             <div class="readonly">{{
    > field.contents }}</div>
    >
    >
    > Traceback:
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\forms\forms.py" in
    > __getitem__
    >   163.             field = self.fields[name]
    >
    > During handling of the above exception ('groups'), another
    exception
    > occurred:
    >
    > File
    >
    
"D:\Users\mike\envs\xxex3\lib\site-packages\django\core\handlers\exception.py"

    > in inner
    >   34.             response = get_response(request)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\core\handlers\base.py"

    > in _get_response
    >   145.                 response =
    > self.process_exception_by_middleware(e, request)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\core\handlers\base.py"

    > in _get_response
    >   143.                 response = response.render()
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\response.py"

    > in render
    >   106.             self.content = self.rendered_content
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\response.py"

    > in rendered_content
    >   83.         content = template.render(context, self._request)
    >
    > File
    >
    
"D:\Users\mike\envs\xxex3\lib\site-packages\django\template\backends\django.py"

    > in render
    >   61.             return self.template.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render
    >   171.                     return self._render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in _render
    >   163.         return self.nodelist.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render
    >   937.                 bit = node.render_annotated(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render_annotated
    >   904.             return self.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\loader_tags.py"

    > in render
    >   150.             return compiled_parent._render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in _render
    >   163.         return self.nodelist.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render
    >   937.                 bit = node.render_annotated(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render_annotated
    >   904.             return self.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\loader_tags.py"

    > in render
    >   150.             return compiled_parent._render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in _render
    >   163.         return self.nodelist.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render
    >   937.                 bit = node.render_annotated(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render_annotated
    >   904.             return self.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\loader_tags.py"

    > in render
    >   62.                 result = block.nodelist.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render
    >   937.                 bit = node.render_annotated(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render_annotated
    >   904.             return self.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\loader_tags.py"

    > in render
    >   62.                 result = block.nodelist.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render
    >   937.                 bit = node.render_annotated(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render_annotated
    >   904.             return self.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\defaulttags.py"

    > in render
    >   209. nodelist.append(node.render_annotated(context))
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render_annotated
    >   904.             return self.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\loader_tags.py"

    > in render
    >   188.             return template.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render
    >   173.                 return self._render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in _render
    >   163.         return self.nodelist.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render
    >   937.                 bit = node.render_annotated(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render_annotated
    >   904.             return self.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\defaulttags.py"

    > in render
    >   209. nodelist.append(node.render_annotated(context))
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\base.py"
    > in render_annotated
    >   904.             return self.render(context)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\template\defaulttags.py"

    > in render
    >   165.                 values = list(values)
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\contrib\admin\helpers.py"

    > in __iter__
    >   113.                 yield AdminField(self.form, field,
    is_first=(i
    > == 0))
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\contrib\admin\helpers.py"

    > in __init__
    >   125.         self.field = form[field]  # A
    django.forms.BoundField
    > instance
    >
    > File
    >
    "D:\Users\mike\envs\xxex3\lib\site-packages\django\forms\forms.py" in
    > __getitem__
    >   169.                     ', '.join(sorted(f for f in
    self.fields)),
    >
    > Exception Type: KeyError at /admin/common/user/59/change/
    > Exception Value: "Key 'groups' not found in 'UserForm'. Choices
    are:
    > email, first_name, is_active, is_staff, last_name, password,
    username."
    >

-- You received this message because you are subscribed to the Google
    Groups "Django users" group.
    To unsubscribe from this group and stop receiving emails from it,
    send an email to django-users+unsubscr...@googlegroups.com
    <mailto:django-users%2bunsubscr...@googlegroups.com>.
    To view this discussion on the web visit
    
https://groups.google.com/d/msgid/django-users/52cffdfe-9e4c-5c49-7f97-3e6c5857bcc2%40dewhirst.com.au.

--
You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscr...@googlegroups.com <mailto:django-users+unsubscr...@googlegroups.com>. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAD4ANxXAtDEMr%3DT3buT9OuVrndt8AiJYaL9Gv9MfmyNcjJMWSA%40mail.gmail.com <https://groups.google.com/d/msgid/django-users/CAD4ANxXAtDEMr%3DT3buT9OuVrndt8AiJYaL9Gv9MfmyNcjJMWSA%40mail.gmail.com?utm_medium=email&utm_source=footer>.

--
You received this message because you are subscribed to the Google Groups "Django 
users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/30ff813b-4a49-8d48-5ccf-05dcb243278e%40dewhirst.com.au.

Reply via email to