summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2023-07-07 08:06:01 +0200
committerGitHub <noreply@github.com>2023-07-07 08:06:01 +0200
commitf64fd47a7627ed6ffe2df2a32ded6ee528a784eb (patch)
tree1abf1f8f945e9b72a72d31ec00f356e1088c4538 /django
parentd569c1dcfeb26ca9ee391e5dfeadedf2b5ed4253 (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.py34
-rw-r--r--django/contrib/admin/filters.py12
-rw-r--r--django/contrib/admin/options.py37
-rw-r--r--django/contrib/admin/sites.py8
-rw-r--r--django/contrib/admin/utils.py4
-rw-r--r--django/contrib/admin/views/autocomplete.py6
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.