﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
19710	ModelAdmin exclude behaviour not consistent with ModelAdmin behaviour	Rafal Stozek	nobody	"A ModelAdmin like this:

{{{
from django.contrib.auth.admin import UserAdmin as UserAdminBase
from django.contrib.auth.models import Group
from django.contrib import admin
from .models import User


class UserAdmin(UserAdminBase):
    exclude = ('user_permissions', 'groups')
    def has_delete_permission(self, request, obj=None):
        # don't allow user removal
        return False


admin.site.register(User, UserAdmin)
admin.site.unregister(Group)
}}}

(Note: I'm using custom user model so I don't have to unregister old UserAdmin)

will result in a traceback when trying to visit user admin's change view:

{{{
Traceback:
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py"" in get_response
  140.                     response = response.render()
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/response.py"" in render
  105.             self.content = self.rendered_content
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/response.py"" in rendered_content
  82.         content = template.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  140.             return self._render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in _render
  134.         return self.nodelist.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  830.                 bit = self.render_node(node, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/debug.py"" in render_node
  74.             return node.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/loader_tags.py"" in render
  124.         return compiled_parent._render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in _render
  134.         return self.nodelist.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  830.                 bit = self.render_node(node, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/debug.py"" in render_node
  74.             return node.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/loader_tags.py"" in render
  124.         return compiled_parent._render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in _render
  134.         return self.nodelist.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  830.                 bit = self.render_node(node, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/debug.py"" in render_node
  74.             return node.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/loader_tags.py"" in render
  63.             result = block.nodelist.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  830.                 bit = self.render_node(node, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/debug.py"" in render_node
  74.             return node.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/loader_tags.py"" in render
  63.             result = block.nodelist.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  830.                 bit = self.render_node(node, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/debug.py"" in render_node
  74.             return node.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/defaulttags.py"" in render
  188.                         nodelist.append(node.render(context))
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/loader_tags.py"" in render
  156.         return self.render_template(self.template, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/loader_tags.py"" in render_template
  138.         output = template.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  140.             return self._render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in _render
  134.         return self.nodelist.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  830.                 bit = self.render_node(node, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/debug.py"" in render_node
  74.             return node.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/defaulttags.py"" in render
  367.         return strip_spaces_between_tags(self.nodelist.render(context).strip())
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  830.                 bit = self.render_node(node, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/debug.py"" in render_node
  74.             return node.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/defaulttags.py"" in render
  188.                         nodelist.append(node.render(context))
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/defaulttags.py"" in render
  284.                 return nodelist.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in render
  830.                 bit = self.render_node(node, context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/debug.py"" in render_node
  74.             return node.render(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/defaulttags.py"" in render
  277.                     match = condition.eval(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/defaulttags.py"" in eval
  828.         return self.value.resolve(context, ignore_failures=True)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in resolve
  578.                 obj = self.var.resolve(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in resolve
  728.             value = self._resolve_lookup(context)
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/template/base.py"" in _resolve_lookup
  779.                             current = current()
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/contrib/admin/helpers.py"" in errors
  115.         return mark_safe('\n'.join([self.form[f].errors.as_ul() for f in self.fields if f not in self.readonly_fields]).strip('\n'))
File ""/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/forms.py"" in __getitem__
  111.             raise KeyError('Key %r not found in Form' % name)

Exception Type: KeyError at /admin/accounts/user/1/
Exception Value: u""Key 'groups' not found in Form""
}}}

It's because ModelForm and ModelAdmin helpers produce different set of fields when there are both fieldsets/fields and exclude attributes specified on ModelAdmin. This affects InlineModelAdmin too.

There are four ways to fix it:

1) Just inform user that it's impossible to use both fields/fieldsets and exclude
2) Remove fields which don't exist in form from formset before passing it to helpers.AdminForm or helpers.InlineAdminFormset
3) Just like 2), but do this in helpers.AdminForm and helpers.InlineAdminFormset __init__() method
4) Skip non-existent fields in method {{{__iter__()}}} of helpers.Fieldset and helpers.InlineFieldset (note: ""field"" variable in {{{__iter__()}}} can also be a tuple or a list).

Changing get_fieldsets() may be a bad idea because it's something that people override (UserAdmin does this for example)."	Bug	new	contrib.admin	1.4	Normal				Accepted	0	0	0	0	0	0
