diff options
| author | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-07-07 08:06:01 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-07-07 08:06:01 +0200 |
| commit | f64fd47a7627ed6ffe2df2a32ded6ee528a784eb (patch) | |
| tree | 1abf1f8f945e9b72a72d31ec00f356e1088c4538 /django | |
| parent | d569c1dcfeb26ca9ee391e5dfeadedf2b5ed4253 (diff) | |
Fixed #9602 -- Added AdminSite.get_model_admin().
This allows retrieving an admin class for the given model class without
using internal attributes.
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/admin/checks.py | 34 | ||||
| -rw-r--r-- | django/contrib/admin/filters.py | 12 | ||||
| -rw-r--r-- | django/contrib/admin/options.py | 37 | ||||
| -rw-r--r-- | django/contrib/admin/sites.py | 8 | ||||
| -rw-r--r-- | django/contrib/admin/utils.py | 4 | ||||
| -rw-r--r-- | django/contrib/admin/views/autocomplete.py | 6 |
6 files changed, 66 insertions, 35 deletions
diff --git a/django/contrib/admin/checks.py b/django/contrib/admin/checks.py index 45d895dff0..f5aa9b55d4 100644 --- a/django/contrib/admin/checks.py +++ b/django/contrib/admin/checks.py @@ -220,6 +220,8 @@ class BaseModelAdminChecks: ManyToManyField and that the item has a related ModelAdmin with search_fields defined. """ + from django.contrib.admin.sites import NotRegistered + try: field = obj.model._meta.get_field(field_name) except FieldDoesNotExist: @@ -234,8 +236,9 @@ class BaseModelAdminChecks: obj=obj, id="admin.E038", ) - related_admin = obj.admin_site._registry.get(field.remote_field.model) - if related_admin is None: + try: + related_admin = obj.admin_site.get_model_admin(field.remote_field.model) + except NotRegistered: return [ checks.Error( 'An admin for model "%s" has to be registered ' @@ -248,19 +251,20 @@ class BaseModelAdminChecks: id="admin.E039", ) ] - elif not related_admin.search_fields: - return [ - checks.Error( - '%s must define "search_fields", because it\'s ' - "referenced by %s.autocomplete_fields." - % ( - related_admin.__class__.__name__, - type(obj).__name__, - ), - obj=obj.__class__, - id="admin.E040", - ) - ] + else: + if not related_admin.search_fields: + return [ + checks.Error( + '%s must define "search_fields", because it\'s ' + "referenced by %s.autocomplete_fields." + % ( + related_admin.__class__.__name__, + type(obj).__name__, + ), + obj=obj.__class__, + id="admin.E040", + ) + ] return [] def _check_raw_id_fields(self, obj): diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py index f6f6d0dd6f..197d39bf21 100644 --- a/django/contrib/admin/filters.py +++ b/django/contrib/admin/filters.py @@ -257,10 +257,16 @@ class RelatedFieldListFilter(FieldListFilter): """ Return the model admin's ordering for related field, if provided. """ - related_admin = model_admin.admin_site._registry.get(field.remote_field.model) - if related_admin is not None: + from django.contrib.admin.sites import NotRegistered + + try: + related_admin = model_admin.admin_site.get_model_admin( + field.remote_field.model + ) + except NotRegistered: + return () + else: return related_admin.get_ordering(request) - return () def field_choices(self, field, request, model_admin): ordering = self.field_admin_ordering(field, request, model_admin) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index b0635669e9..f9760664dd 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -160,6 +160,8 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): If kwargs are given, they're passed to the form Field's constructor. """ + from django.contrib.admin.sites import NotRegistered + # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: @@ -185,23 +187,27 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: - related_modeladmin = self.admin_site._registry.get( - db_field.remote_field.model - ) - wrapper_kwargs = {} - if related_modeladmin: - wrapper_kwargs.update( - can_add_related=related_modeladmin.has_add_permission(request), - can_change_related=related_modeladmin.has_change_permission( + try: + related_modeladmin = self.admin_site.get_model_admin( + db_field.remote_field.model + ) + except NotRegistered: + wrapper_kwargs = {} + else: + wrapper_kwargs = { + "can_add_related": related_modeladmin.has_add_permission( request ), - can_delete_related=related_modeladmin.has_delete_permission( + "can_change_related": related_modeladmin.has_change_permission( request ), - can_view_related=related_modeladmin.has_view_permission( + "can_delete_related": related_modeladmin.has_delete_permission( request ), - ) + "can_view_related": related_modeladmin.has_view_permission( + request + ), + } formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.remote_field, @@ -246,8 +252,13 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): ordering. Otherwise don't specify the queryset, let the field decide (return None in that case). """ - related_admin = self.admin_site._registry.get(db_field.remote_field.model) - if related_admin is not None: + from django.contrib.admin.sites import NotRegistered + + try: + related_admin = self.admin_site.get_model_admin(db_field.remote_field.model) + except NotRegistered: + return None + else: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.remote_field.model._default_manager.using(db).order_by( diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index 1e289876f8..41ce85db79 100644 --- a/django/contrib/admin/sites.py +++ b/django/contrib/admin/sites.py @@ -121,7 +121,7 @@ class AdminSite: ) if self.is_registered(model): - registered_admin = str(self._registry[model]) + registered_admin = str(self.get_model_admin(model)) msg = "The model %s is already registered " % model.__name__ if registered_admin.endswith(".ModelAdmin"): # Most likely registered without a ModelAdmin subclass. @@ -166,6 +166,12 @@ class AdminSite: """ return model in self._registry + def get_model_admin(self, model): + try: + return self._registry[model] + except KeyError: + raise NotRegistered(f"The model {model.__name__} is not registered.") + def add_action(self, action, name=None): """ Register an action to be available globally. diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py index bb5f950122..92ef1639b4 100644 --- a/django/contrib/admin/utils.py +++ b/django/contrib/admin/utils.py @@ -144,7 +144,9 @@ def get_deleted_objects(objs, request, admin_site): no_edit_link = "%s: %s" % (capfirst(opts.verbose_name), obj) if admin_site.is_registered(model): - if not admin_site._registry[model].has_delete_permission(request, obj): + if not admin_site.get_model_admin(model).has_delete_permission( + request, obj + ): perms_needed.add(opts.verbose_name) try: admin_url = reverse( diff --git a/django/contrib/admin/views/autocomplete.py b/django/contrib/admin/views/autocomplete.py index 130848b551..051b9a31b9 100644 --- a/django/contrib/admin/views/autocomplete.py +++ b/django/contrib/admin/views/autocomplete.py @@ -74,6 +74,8 @@ class AutocompleteJsonView(BaseListView): Raise Http404 if the target model admin is not configured properly with search_fields. """ + from django.contrib.admin.sites import NotRegistered + term = request.GET.get("term", "") try: app_label = request.GET["app_label"] @@ -97,8 +99,8 @@ class AutocompleteJsonView(BaseListView): except AttributeError as e: raise PermissionDenied from e try: - model_admin = self.admin_site._registry[remote_model] - except KeyError as e: + model_admin = self.admin_site.get_model_admin(remote_model) + except NotRegistered as e: raise PermissionDenied from e # Validate suitability of objects. |
