#32659 closed Bug (needsinfo)
Autocomplete field: The results could not be loaded.
Reported by: | honyczek | Owned by: | nobody |
---|---|---|---|
Component: | contrib.admin | Version: | 3.2 |
Severity: | Normal | Keywords: | |
Cc: | Johannes Maron, Jonathan Willitts | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I use autocomplete field and which with Django 3.1 worked well, after updating to 3.2 it returns only a message: The results could not be loaded. If I look into browser console, I see a try to open url autocomplete/ with status 403 Forbidden. I thought it is a problem with application permissions, but after I've given superuser permission to the user, it is the same.
Change History (15)
comment:1 by , 4 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
comment:2 by , 4 years ago
I've encountered this myself tonight in one of my projects. For me the problem was caching of static files. I use Django Storages with S3 and Cloudfront and even after invalidating files on AWS and re-running collect static I get the HTTP403. If I disable django-storages it "fixes" it. It's not a solution I can use for production. I'm confused as to why serving static files from a different domain would be causing a 403 though /admin/autocomplete/
*update*
The issue is that the request hits django.contrib.admin.views.autocomplete.AutocompleteJsonView.process_request where a KeyError
occurs for app_label because request.GET is an empty QueryDict
- update 2*
When Django Storages is turned off request.GET is the following
<QueryDict: {'app_label': ['example'], 'model_name': ['examplemodel'], 'field_name': ['lookup']}>
follow-up: 4 comment:3 by , 4 years ago
I was running into the exact same issue after updating from 3.1 to 3.2.
Basically when filling in data into the select2 inputs, the query made was incomplete. Only the term
param was set. The caused the process_request
method in django.contrib.admin.views.autocomplete
to raise an PermissionDenied
exception. Here is the part that i mean:
term = request.GET.get('term', '') try: app_label = request.GET['app_label'] model_name = request.GET['model_name'] field_name = request.GET['field_name'] except KeyError as e: raise PermissionDenied from e
Maybe there should be a different exception raised here for clarity.
To fix the issue I just ran the collectstatic
command and the problems were gone. So most likely this is caused by an old and incompatible js library still in the static files.
comment:4 by , 4 years ago
Replying to Nicolas Meisberger:
To fix the issue I just ran the
collectstatic
command and the problems were gone. So most likely this is caused by an old and incompatible js library still in the static files.
Thanks for the tip, which resolved me the issue. So definitely, it is not a bug.
comment:5 by , 4 years ago
I ran collectstatic
but the issue persists. below the error logs:
django_1 | Forbidden (Permission denied): /admin/autocomplete/ django_1 | Traceback (most recent call last): django_1 | File "/usr/local/lib/python3.8/site-packages/django/utils/datastructures.py", line 76, in __getitem__ django_1 | list_ = super().__getitem__(key) django_1 | KeyError: 'app_label' django_1 | django_1 | During handling of the above exception, another exception occurred: django_1 | django_1 | Traceback (most recent call last): django_1 | File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/views/autocomplete.py", line 61, in process_request django_1 | app_label = request.GET['app_label'] django_1 | File "/usr/local/lib/python3.8/site-packages/django/utils/datastructures.py", line 78, in __getitem__ django_1 | raise MultiValueDictKeyError(key) django_1 | django.utils.datastructures.MultiValueDictKeyError: 'app_label' django_1 | django_1 | The above exception was the direct cause of the following exception: django_1 | django_1 | Traceback (most recent call last): django_1 | File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner django_1 | response = get_response(request) django_1 | File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response django_1 | response = wrapped_callback(request, *callback_args, **callback_kwargs) django_1 | File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 250, in wrapper django_1 | return self.admin_view(view, cacheable)(*args, **kwargs) django_1 | File "/usr/local/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view django_1 | response = view_func(request, *args, **kwargs) django_1 | File "/usr/local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func django_1 | response = view_func(request, *args, **kwargs) django_1 | File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 232, in inner django_1 | return view(request, *args, **kwargs) django_1 | File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 417, in autocomplete_view django_1 | return AutocompleteJsonView.as_view(admin_site=self)(request) django_1 | File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view django_1 | return self.dispatch(request, *args, **kwargs) django_1 | File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 98, in dispatch django_1 | return handler(request, *args, **kwargs) django_1 | File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/views/autocomplete.py", line 20, in get django_1 | self.term, self.model_admin, self.source_field, to_field_name = self.process_request(request) django_1 | File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/views/autocomplete.py", line 65, in process_request django_1 | raise PermissionDenied from e django_1 | django.core.exceptions.PermissionDenied django_1 | [03/May/2021 22:17:04] "GET /admin/autocomplete/ HTTP/1.1" 403 135
comment:6 by , 4 years ago
I have the same problem. I ran collectstatic
but it still did not work. And it turns out, the web browser is still caching the JavaScript.
Try it with the your web browser on incognito mode, or clear your cache. It should solve the issue.
comment:8 by , 4 years ago
Quick Update:
I noticed that static files not really getting updated after running collectstatic
. And it turned out that I need to remove/comment STATICFILES_DIRS
from my settings.py then run collectstatic
which really updated the files and the above issue was fixed.
follow-up: 14 comment:9 by , 3 years ago
This had nothing to do with caching or collectstatic
for me. I traced it to the admin_site
attribute of AutocompleteJsonView
.The view tries to get the model_admin
class for the remote model
from Django's default admin site. If you registered your remote model in a custom admin site a KeyError
is raised (line 84). This behavior has changed from 3.1.12 to 3.2.0. See changes in commit 3071660acfbdf4b5c59457c8e9dc345d5e8894c5.
A quick/dirty fix is to scan through the registered AdminSites
in all_sites
for the admin_site
that has registered the remote_model
:
# django/contrib/admin/views/autocomplete.py from django.contrib.admin.sites import all_sites class AutocompleteJsonView(BaseListView): .... def process_request(self, request): .... # find the correct admin site for this remote model try: admin_site = [s for s in all_sites if s.is_registered(remote_model)][0] except IndexError as e: raise PermissionDenied from e # continue as before and get the model admin class from the admin site try: model_admin = admin_site._registry[remote_model] except KeyError as e: raise PermissionDenied from e # Validate suitability of objects. ....
Note that you cannot just register the remote_model
with the default admin site. The remote_model
needs to be registered to the same admin class as the source_model
.
comment:10 by , 3 years ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
comment:11 by , 3 years ago
Cc: | added |
---|---|
Resolution: | → needsinfo |
Status: | new → closed |
Erik, thanks for extra details, however I still cannot reproduce this issue.
The view tries to get the
model_admin
class for theremote_model
from Django's default admin site.
As far as I'm aware that's not true, the view uses an admin site in which it's registered.
Can you provide a sample project?
comment:12 by , 3 years ago
Cc: | added |
---|
comment:13 by , 3 years ago
ok, you are correct. This is not a bug.
I had this issue because I was incorrectly declaring url paths in the urls.py
for my project. The issue is not with sites.py
nor autocomplete.py
.
The way I setup the admin URLs for all the admin sites in the project risked non-unique urls; namely, for autocomplete
.
# WRONG
path("admin/", app_one_admin.urls), # reverses toadmin/autocomplete
will always hit this AdminSite !!
path("admin/", app_two_admin.urls), # reverses toadmin/autocomplete
path("admin/", app_three_admin.urls), # reverses toadmin/autocomplete
path("admin/", admin.site.urls), # reverses toadmin/autocomplete
The better way is:
# better
path("app_one_admin/", app_one_admin.urls), # reverses toapp_one_admin/autocomplete
path("app_two_admin/", app_two_admin.urls), # reverses toapp_two_admin/autocomplete
path("app_three_admin/", app_three_admin.urls), # reverses toapp_three_admin/autocomplete
path("admin/", admin.site.urls), # reverses toadmin/autocomplete
See docs https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#multiple-admin-sites-in-the-same-urlconf
comment:14 by , 3 years ago
I've run into this exact issue on my project. I'm assuming there is a conflict between the Django Autocomplete Light dependency and Django 3.2 autocomplete_fields.
I'm looking at your example fix below, but I'm not sure where you are implementing this in your Django Project?
Replying to Erik van Widenfelt:
This had nothing to do with caching or
collectstatic
for me. I traced it to theadmin_site
attribute ofAutocompleteJsonView
.The view tries to get themodel_admin
class for theremote model
from Django's default admin site. If you registered your remote model in a custom admin site aKeyError
is raised (line 84). This behavior has changed from 3.1.12 to 3.2.0. See changes in commit 3071660acfbdf4b5c59457c8e9dc345d5e8894c5.
A quick/dirty fix is to scan through the registered
AdminSites
inall_sites
for theadmin_site
that has registered theremote_model
:
# django/contrib/admin/views/autocomplete.py from django.contrib.admin.sites import all_sites class AutocompleteJsonView(BaseListView): .... def process_request(self, request): .... # find the correct admin site for this remote model try: admin_site = [s for s in all_sites if s.is_registered(remote_model)][0] except IndexError as e: raise PermissionDenied from e # continue as before and get the model admin class from the admin site try: model_admin = admin_site._registry[remote_model] except KeyError as e: raise PermissionDenied from e # Validate suitability of objects. ....Note that you cannot just register the
remote_model
with the default admin site. Theremote_model
needs to be registered to the same admin class as thesource_model
.
comment:15 by , 3 years ago
The reason for this behavior is a change in the Javascript code in the file contrib/admin/static/admin/js/autocomplete.js from version 3.1 to 3.2 (see below).
In addition to running ./manage.py collectstatic
it is also necessary to refresh the browser cache. That can be done by going to the address <site>/static/admin/js/autocomplete.js
and clicking Reload.
autocomplete.js in v3.1:
'use strict'; { const $ = django.jQuery; const init = function($element, options) { const settings = $.extend({ ajax: { data: function(params) { return { term: params.term, page: params.page }; } } }, options); $element.select2(settings); }; ...
autocomplete.js in v3.2:
'use strict'; { const $ = django.jQuery; const init = function($element, options) { const settings = $.extend({ ajax: { data: function(params) { return { term: params.term, page: params.page, app_label: $element.data('app-label'), model_name: $element.data('model-name'), field_name: $element.data('field-name') }; } } }, options); $element.select2(settings); }; ...
Thanks for this report, however autocomplete works for me. I don't think you've explained the issue in enough detail to confirm a bug in Django (see e.g. #32619). Please reopen the ticket if you can debug your issue and provide details about why and where Django is at fault.