Opened 9 years ago

Closed 9 years ago

#24187 closed Uncategorized (invalid)

admin.ModelAdmin base-class Cross referencing fields

Reported by: Charles Owned by: nobody
Component: contrib.admin Version: 1.7
Severity: Release blocker Keywords: ModelAdmin
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hello,

I have found a bug on the ModelAdmin, I will try my best to explain.

My Environment is as follows:
Vagrant / Debian VM
nginx webserver
uWSGI webserver
Django 1.7.3
Grappelli admin panel

Basically I have a website, which has 2 types of articles Global and Local articles, each model inherit from a base (abstract) model:

class ArticleBase(models.Model):
    title = models.CharField(max_length=100, null=False, help_text="Character limit: 100")   
    body = club_fields.WysiwygField(blank=True)
    etc...

    class Meta(object):
         abstract = True

class Article(ArticleBase):
    # Can't be set in base as is unique in Global but not unique by itself in localised article
    slug = models.SlugField(max_length=100, unique=True)

    class Meta(object):
        index_together = [
            ["slug", "status"],
        ]
        ordering = ("-creation_date",)

class LocalisedArticle(ArticleBase):
    # Can't be set in base as is unique in Global but not unique by itself in localised article
    slug = models.SlugField(max_length=100)
    locale = models.CharField(max_length=10, null=False, choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE)

    class Meta(object):
        unique_together = (
            ("slug", "locale")
        )
        index_together = [
            ["slug", "status", "locale"],
        ]
        ordering = ("-pub_date",)

And I have setup the admin classes to follow a similar suit, where each article admin inherits from a baseclass which sets up fieldsets etc..

class ArticleAdmin(ImageCroppingMixin,admin.ModelAdmin):
    ordering = ("-pub_date",)
    list_display = ["title", "pub_date", "status", "update_date"]

    prepopulated_fields = {"slug": ("title", ), }
    exclude = ("overview_image", "hero_image")
    fieldsets = [
        ["Meta", {
            "fields": ("title", "heading_intro", "heading_sub", "slug", "status", "pub_date", "meta_description", "social_description", "article_type", "category", "download")
        }],
        ["Content", {
            "fields": ("body", "image", "overview_crop", "overview_alignment", "hero_crop", "video_id", "discussion_question", "disable_comments")
        }],
    ]

class GlobalArticleAdmin(ArticleAdmin):
    inlines = [
        ArticleInlineImageAdmin,
        ArticleCarouselInlineAdmin
    ]

class LocalisedArticleAdmin(ArticleAdmin):
    list_filter = ("locale", "status")
    inlines = [
        LocalisedArticleInlineAdmin,
        LocalisedArticleCarouselInlineAdmin,
        ArticleCommentInlineAdmin,
    ]

    def get_list_display(self, request):
        list_display = super(LocalisedArticleAdmin, self).get_list_display(request)
        return list_display + ['locale']

    def get_fieldsets(self, request, obj=None):
        fieldsets = super(LocalisedArticleAdmin, self).get_fieldsets(request, obj)
        for i, fieldset in enumerate(fieldsets):
            if fieldset[0] == 'Meta':
                if 'locale' not in fieldset[1]['fields']:
                    fieldsets[i][1]['fields'] += ('locale',)
                break
        return fieldsets

    def get_form(self, request, obj=None, **kwargs):
        form = super(LocalisedArticleAdmin, self).get_form(request, obj, **kwargs)
        editable_locales = self.get_editable_locales(request)
        locale_choices = []
        for lang in settings.LANGUAGES:
            if lang[0] in editable_locales:
                locale_choices.append(lang)

        form.base_fields['locale'].choices = locale_choices
        return form

admin.site.register(Article, GlobalArticleAdmin)
admin.site.register(LocalisedArticle, LocalisedArticleAdmin)

In the localised article admin class, I have overloaded certain methods to include the Locale Field in the forms, with appropriate editable locales based on custom model permissions (I haven't included the entire class as they are quite long, and I don't think the most part is necessary)

The Bug

Now, the bug is that, I can view the global article admin page no problems if I go to that admin page first, but as soon as I goto the localised article admin and save a localised article model, and go back to the global article admin page I get the following error:

Request Method: GET
Request URL: http://localhost:8000/admin/my_app/article/1/

Django Version: 1.7.3
Python Version: 2.7.3
Installed Applications:
(u'django.contrib.auth',
 u'django.contrib.contenttypes',
 u'django.contrib.sessions',
 u'django.contrib.messages',
 u'django.contrib.staticfiles',
 u'compressor',
 u'imagekit',
 u'haystack',
 u'my_app',
 u'grappelli.dashboard',
 u'grappelli',
 u'django.contrib.admin',
 u'django_user_agents',
 u'easy_thumbnails',
 u'image_cropping')
Installed Middleware:
(u'django.contrib.sessions.middleware.SessionMiddleware',
 u'django.middleware.locale.LocaleMiddleware',
 u'django.middleware.common.CommonMiddleware',
 u'django.middleware.csrf.CsrfViewMiddleware',
 u'django.contrib.auth.middleware.AuthenticationMiddleware',
 u'django.contrib.messages.middleware.MessageMiddleware',
 u'django.middleware.clickjacking.XFrameOptionsMiddleware',
 u'django_user_agents.middleware.UserAgentMiddleware')


Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  111.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in wrapper
  583.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view
  105.                     response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/cache.py" in _wrapped_view_func
  52.         response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/sites.py" in inner
  206.             return view(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in change_view
  1456.         return self.changeform_view(request, object_id, form_url, extra_context)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapper
  29.             return bound_func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view
  105.                     response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in bound_func
  25.                 return func.__get__(self, type(self))(*args2, **kwargs2)
File "/usr/local/lib/python2.7/dist-packages/django/db/transaction.py" in inner
  394.                 return func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in changeform_view
  1393.         ModelForm = self.get_form(request, obj)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in get_form
  670.                              % (e, self.__class__.__name__))

Exception Type: FieldError at /admin/my_app/article/1/
Exception Value: Unknown field(s) (locale) specified for Article. Check fields/fieldsets/exclude attributes of class GlobalArticleAdmin.

Now, no where in the Article model, ArticleAdmin base class, or the GlobalArticleAdmin class is the field 'locale' referenced, the ONLY place this field is referenced is in the LocalisedArticle model and the LocalArticleAdmin class overloaded form and field methods.. and as I say, this only comes up after I save a Localiased article, if I reload the uWSGI instance, I can access the GlobalArticleAdmin no problem.. and this does not happen if I remove the ArticleAdmin base class, and duplicate the code in both admin classes..

I have no idea why the GlobalArticleAdmin is trying to add a 'locale' field to the admin page..

Please advise.

Change History (1)

comment:1 by Tim Graham, 9 years ago

Resolution: invalid
Status: newclosed

This line looks suspicious to me fieldsets[i][1]['fields'] += ('locale',).

Please see TicketClosingReasons/UseSupportChannels.

Note: See TracTickets for help on using tickets.
Back to Top