From 560a1ba9a0e4994db09922faf7c9c49e20f19fa5 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Tue, 16 Jan 2007 00:09:53 +0000 Subject: [PATCH] newforms-admin: A model's 'class Admin' is now dynamically/magically converted to be a subclass of django.contrib.admin.options.ModelAdmin, and the admin site now uses that class rather than the separate AdminOptions class (for list_display only). This means means 'class Admin' can override any functionality of ModelAdmin, such as has_add_permission(), etc. git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4328 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/admin/options.py | 5 ++++- django/contrib/admin/templatetags/admin_list.py | 6 +++--- django/contrib/admin/views/main.py | 9 +++++---- django/db/models/base.py | 10 +++++++++- django/db/models/options.py | 4 ++-- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 6c7ffd237d..c63d262d33 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -32,6 +32,9 @@ def unquote(s): class ModelAdmin(object): "Encapsulates all admin options and functionality for a given model." + + list_display = ('__str__',) + def __init__(self, model): self.model = model self.opts = model._meta @@ -266,7 +269,7 @@ class ModelAdmin(object): if not self.has_change_permission(request, None): raise PermissionDenied try: - cl = ChangeList(request, self.model) + cl = ChangeList(request, self.model, self.list_display) except IncorrectLookupParameters: # Wacky lookup parameters were given, so redirect to the main # changelist page, without parameters, and pass an 'invalid=1' diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index 3c0c6f0ac2..67cc110ad7 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -69,7 +69,7 @@ pagination = register.inclusion_tag('admin/pagination.html')(pagination) def result_headers(cl): lookup_opts = cl.lookup_opts - for i, field_name in enumerate(lookup_opts.admin.list_display): + for i, field_name in enumerate(cl.list_display): try: f = lookup_opts.get_field(field_name) except models.FieldDoesNotExist: @@ -108,7 +108,7 @@ def _boolean_icon(field_val): def items_for_result(cl, result): first = True pk = cl.lookup_opts.pk.attname - for field_name in cl.lookup_opts.admin.list_display: + for field_name in cl.list_display: row_class = '' try: f = cl.lookup_opts.get_field(field_name) @@ -172,7 +172,7 @@ def items_for_result(cl, result): if result_repr == '': result_repr = ' ' # If list_display_links not defined, add the link tag to the first field - if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links: + if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links: table_tag = {True:'th', False:'td'}[first] first = False url = cl.url_for_result(result) diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 721f3453e5..522c326c17 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -81,7 +81,7 @@ def model_admin_view(request, app_label, model_name, rest_of_url): raise Http404("App %r, model %r, not found" % (app_label, model_name)) if not model._meta.admin: raise Http404("This object has no admin interface.") - mav = ModelAdmin(model) + mav = model._meta.ModelAdmin(model) return mav(request, rest_of_url) model_admin_view = staff_member_required(never_cache(model_admin_view)) @@ -292,11 +292,12 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current perms_needed.add(related.opts.verbose_name) class ChangeList(object): - def __init__(self, request, model): + def __init__(self, request, model, list_display): self.model = model self.opts = model._meta self.lookup_opts = self.opts self.manager = self.opts.admin.manager + self.list_display = list_display # Get search parameters from the query string. try: @@ -404,7 +405,7 @@ class ChangeList(object): if params.has_key(ORDER_VAR): try: try: - f = lookup_opts.get_field(lookup_opts.admin.list_display[int(params[ORDER_VAR])]) + f = lookup_opts.get_field(self.list_display[int(params[ORDER_VAR])]) except models.FieldDoesNotExist: pass else: @@ -431,7 +432,7 @@ class ChangeList(object): if self.lookup_opts.admin.list_select_related: qs = qs.select_related() else: - for field_name in self.lookup_opts.admin.list_display: + for field_name in self.list_display: try: f = self.lookup_opts.get_field(field_name) except models.FieldDoesNotExist: diff --git a/django/db/models/base.py b/django/db/models/base.py index 13209a97ac..d4bb0ae350 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -130,8 +130,16 @@ class Model(object): def add_to_class(cls, name, value): if name == 'Admin': assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value)) + from django.contrib.admin.options import ModelAdmin + # Dynamically create a new ModelAdmin class, which is a subclass + # of both ModelAdmin and the 'class Admin' on this model. The + # resulting class is same as if the 'class Admin' were a subclass + # of ModelAdmin. + cls._meta.ModelAdmin = type('ModelAdmin', (value, ModelAdmin), {}) + # This AdminOptions stuff is legacy and will eventually be removed. value = AdminOptions(**dict([(k, v) for k, v in value.__dict__.items() if not k.startswith('_')])) - if hasattr(value, 'contribute_to_class'): + value.contribute_to_class(cls, name) + elif hasattr(value, 'contribute_to_class'): value.contribute_to_class(cls, name) else: setattr(cls, name, value) diff --git a/django/db/models/options.py b/django/db/models/options.py index ff0d112d16..9c7dfe8dee 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -87,10 +87,10 @@ class Options(object): def __repr__(self): return '' % self.object_name - + def __str__(self): return "%s.%s" % (self.app_label, self.module_name) - + def get_field(self, name, many_to_many=True): "Returns the requested field by name. Raises FieldDoesNotExist on error." to_search = many_to_many and (self.fields + self.many_to_many) or self.fields