Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed #29010, Fixed #29138 -- Added limit_choices_to and to_field sup…
…port to autocomplete fields. * Fixed #29010 -- Added limit_choices_to support to autocomplete fields. * Fixed #29138 -- Allowed autocomplete fields to target a custom to_field rather than the PK.
- Loading branch information
Showing
11 changed files
with
199 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
from django.apps import apps | ||
from django.core.exceptions import FieldDoesNotExist, PermissionDenied | ||
from django.http import Http404, JsonResponse | ||
from django.views.generic.list import BaseListView | ||
|
||
|
||
class AutocompleteJsonView(BaseListView): | ||
"""Handle AutocompleteWidget's AJAX requests for data.""" | ||
paginate_by = 20 | ||
model_admin = None | ||
admin_site = None | ||
|
||
def get(self, request, *args, **kwargs): | ||
""" | ||
|
@@ -15,20 +17,16 @@ def get(self, request, *args, **kwargs): | |
pagination: {more: true} | ||
} | ||
""" | ||
if not self.model_admin.get_search_fields(request): | ||
raise Http404( | ||
'%s must have search_fields for the autocomplete_view.' % | ||
type(self.model_admin).__name__ | ||
) | ||
self.term, self.model_admin, self.source_field, to_field_name = self.process_request(request) | ||
|
||
if not self.has_perm(request): | ||
return JsonResponse({'error': '403 Forbidden'}, status=403) | ||
raise PermissionDenied | ||
|
||
self.term = request.GET.get('term', '') | ||
self.object_list = self.get_queryset() | ||
context = self.get_context_data() | ||
return JsonResponse({ | ||
'results': [ | ||
{'id': str(obj.pk), 'text': str(obj)} | ||
{'id': str(getattr(obj, to_field_name)), 'text': str(obj)} | ||
for obj in context['object_list'] | ||
], | ||
'pagination': {'more': context['page_obj'].has_next()}, | ||
|
@@ -41,11 +39,63 @@ def get_paginator(self, *args, **kwargs): | |
def get_queryset(self): | ||
"""Return queryset based on ModelAdmin.get_search_results().""" | ||
qs = self.model_admin.get_queryset(self.request) | ||
qs = qs.complex_filter(self.source_field.get_limit_choices_to()) | ||
This comment has been minimized.
Sorry, something went wrong. |
||
qs, search_use_distinct = self.model_admin.get_search_results(self.request, qs, self.term) | ||
if search_use_distinct: | ||
qs = qs.distinct() | ||
return qs | ||
|
||
def process_request(self, request): | ||
""" | ||
Validate request integrity, extract and return request parameters. | ||
Since the subsequent view permission check requires the target model | ||
admin, which is determined here, raise PermissionDenied if the | ||
requested app, model or field are malformed. | ||
Raise Http404 if the target model admin is not configured properly with | ||
search_fields. | ||
""" | ||
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 | ||
|
||
# Retrieve objects from parameters. | ||
try: | ||
source_model = apps.get_model(app_label, model_name) | ||
except LookupError as e: | ||
raise PermissionDenied from e | ||
|
||
try: | ||
source_field = source_model._meta.get_field(field_name) | ||
except FieldDoesNotExist as e: | ||
raise PermissionDenied from e | ||
try: | ||
remote_model = source_field.remote_field.model | ||
except AttributeError as e: | ||
raise PermissionDenied from e | ||
try: | ||
model_admin = self.admin_site._registry[remote_model] | ||
except KeyError as e: | ||
raise PermissionDenied from e | ||
|
||
# Validate suitability of objects. | ||
if not model_admin.get_search_fields(request): | ||
raise Http404( | ||
'%s must have search_fields for the autocomplete_view.' % | ||
type(model_admin).__qualname__ | ||
) | ||
|
||
to_field_name = getattr(source_field.remote_field, 'field_name', model_admin.model._meta.pk.name) | ||
This comment has been minimized.
Sorry, something went wrong.
dlis
|
||
if not model_admin.to_field_allowed(request, to_field_name): | ||
raise PermissionDenied | ||
|
||
return term, model_admin, source_field, to_field_name | ||
|
||
def has_perm(self, request, obj=None): | ||
"""Check if user has permission to access the related model.""" | ||
return self.model_admin.has_view_permission(request, obj=obj) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
1 comment
on commit 3071660
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there some docs on how to use this?
ManyToManyRel do not have
get_limit_choices_to
💣