diff --git a/django/contrib/admin/__init__.py b/django/contrib/admin/__init__.py index 2218dfd23f..dc63d9b493 100644 --- a/django/contrib/admin/__init__.py +++ b/django/contrib/admin/__init__.py @@ -2,8 +2,8 @@ # has been referenced in documentation. from django.contrib.admin.decorators import register from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME -from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL -from django.contrib.admin.options import StackedInline, TabularInline +from django.contrib.admin.options import (HORIZONTAL, VERTICAL, + ModelAdmin, StackedInline, TabularInline) from django.contrib.admin.filters import (ListFilter, SimpleListFilter, FieldListFilter, BooleanFieldListFilter, RelatedFieldListFilter, ChoicesFieldListFilter, DateFieldListFilter, AllValuesFieldListFilter) diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index 86ab0f263e..50d089255b 100644 --- a/django/contrib/admin/helpers.py +++ b/django/contrib/admin/helpers.py @@ -4,7 +4,6 @@ from django import forms from django.contrib.admin.utils import (flatten_fieldsets, lookup_field, display_for_field, label_for_field, help_text_for_field) from django.contrib.admin.templatetags.admin_static import static -from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.db.models.fields.related import ManyToManyRel from django.forms.utils import flatatt @@ -257,6 +256,9 @@ class InlineAdminForm(AdminForm): self.model_admin = model_admin self.original = original if original is not None: + # Since this module gets imported in the application's root package, + # it cannot import models from other applications at the module level. + from django.contrib.contenttypes.models import ContentType self.original_content_type_id = ContentType.objects.get_for_model(original).pk self.show_url = original and view_on_site_url is not None self.absolute_url = view_on_site_url diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 50c59a3575..5e883e5a8a 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -17,7 +17,6 @@ from django.contrib.admin.utils import (unquote, flatten_fieldsets, from django.contrib.admin.templatetags.admin_static import static from django.contrib.admin.templatetags.admin_urls import add_preserved_filters from django.contrib.auth import get_permission_codename -from django.contrib.contenttypes.models import ContentType from django.core import checks from django.core.exceptions import PermissionDenied, ValidationError, FieldError, ImproperlyConfigured from django.core.paginator import Paginator @@ -55,6 +54,13 @@ TO_FIELD_VAR = '_to_field' HORIZONTAL, VERTICAL = 1, 2 +def get_content_type_for_model(obj): + # Since this module gets imported in the application's root package, + # it cannot import models from other applications at the module level. + from django.contrib.contenttypes.models import ContentType + return ContentType.objects.get_for_model(obj) + + def get_ul_class(radio_style): return 'radiolist' if radio_style == VERTICAL else 'radiolist inline' @@ -291,7 +297,7 @@ class BaseModelAdmin(six.with_metaclass(RenameBaseModelAdminMethods)): elif self.view_on_site and hasattr(obj, 'get_absolute_url'): # use the ContentType lookup if view_on_site is True return reverse('admin:view_on_site', kwargs={ - 'content_type_id': ContentType.objects.get_for_model(obj).pk, + 'content_type_id': get_content_type_for_model(obj).pk, 'object_id': obj.pk }) @@ -728,7 +734,7 @@ class ModelAdmin(BaseModelAdmin): from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, - content_type_id=ContentType.objects.get_for_model(object).pk, + content_type_id=get_content_type_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION @@ -743,7 +749,7 @@ class ModelAdmin(BaseModelAdmin): from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, - content_type_id=ContentType.objects.get_for_model(object).pk, + content_type_id=get_content_type_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, @@ -760,7 +766,7 @@ class ModelAdmin(BaseModelAdmin): from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, - content_type_id=ContentType.objects.get_for_model(self.model).pk, + content_type_id=get_content_type_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION @@ -1042,7 +1048,7 @@ class ModelAdmin(BaseModelAdmin): 'absolute_url': view_on_site_url, 'form_url': form_url, 'opts': opts, - 'content_type_id': ContentType.objects.get_for_model(self.model).id, + 'content_type_id': get_content_type_for_model(self.model).pk, 'save_as': self.save_as, 'save_on_top': self.save_on_top, 'to_field_var': TO_FIELD_VAR, @@ -1660,7 +1666,7 @@ class ModelAdmin(BaseModelAdmin): app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), - content_type=ContentType.objects.get_for_model(model) + content_type=get_content_type_for_model(model) ).select_related().order_by('action_time') context = dict(self.admin_site.each_context(), diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index f25055baf7..99c46a3e12 100644 --- a/django/contrib/admin/sites.py +++ b/django/contrib/admin/sites.py @@ -1,9 +1,7 @@ from functools import update_wrapper from django.http import Http404, HttpResponseRedirect from django.contrib.admin import ModelAdmin, actions -from django.contrib.admin.forms import AdminAuthenticationForm from django.contrib.auth import logout as auth_logout, REDIRECT_FIELD_NAME -from django.contrib.contenttypes import views as contenttype_views from django.views.decorators.csrf import csrf_protect from django.db.models.base import ModelBase from django.apps import apps @@ -212,6 +210,10 @@ class AdminSite(object): def get_urls(self): from django.conf.urls import patterns, url, include + # Since this module gets imported in the application's root package, + # it cannot import models from other applications at the module level, + # and django.contrib.contenttypes.views imports ContentType. + from django.contrib.contenttypes import views as contenttype_views if settings.DEBUG: self.check_dependencies() @@ -327,6 +329,10 @@ class AdminSite(object): Displays the login form for the given HttpRequest. """ from django.contrib.auth.views import login + # Since this module gets imported in the application's root package, + # it cannot import models from other applications at the module level, + # and django.contrib.admin.forms eventually imports User. + from django.contrib.admin.forms import AdminAuthenticationForm context = dict(self.each_context(), title=_('Log in'), app_path=request.get_full_path(),