9

i have a simple ModelForm:

class MyForm(ModelForm):

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        del self.fields['name']

As you can see, I try to remove a field from the form's field list (the field definitively exists in the model), but I get an Exception:

TemplateSyntaxError at [..]

Caught an exception while rendering: "Key 'name' not found in Form"

I did not write a custom form, so the template where the error occurs is:

/templates/admin/includes/fieldset.html, error at line 4

Any ideas?

-- UPDATE --

The problem appears only in the admin area.

-- UPDATE 2 --

Maybe a trace dump gives more info:

Original Traceback (most recent call last):
  File "/Library/Python/2.5/site-packages/django/template/debug.py", line 71, in render_node
    result = node.render(context)
  File "/Library/Python/2.5/site-packages/django/template/defaulttags.py", line 155, in render
    nodelist.append(node.render(context))
  File "/Library/Python/2.5/site-packages/django/template/defaulttags.py", line 239, in render
    value = bool_expr.resolve(context, True)
  File "/Library/Python/2.5/site-packages/django/template/__init__.py", line 546, in resolve
    obj = self.var.resolve(context)
  File "/Library/Python/2.5/site-packages/django/template/__init__.py", line 687, in resolve
    value = self._resolve_lookup(context)
  File "/Library/Python/2.5/site-packages/django/template/__init__.py", line 722, in _resolve_lookup
    current = current()
  File "/Library/Python/2.5/site-packages/django/contrib/admin/helpers.py", line 81, in errors
    return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]).strip('\n'))
  File "/Library/Python/2.5/site-packages/django/forms/forms.py", line 105, in __getitem__
    raise KeyError('Key %r not found in Form' % name)
KeyError: "Key 'name' not found in Form"

In the admin area, I use the Grapelli-Theme. Maybe this has to do with the problem?

schneck
  • 10,556
  • 11
  • 49
  • 74

5 Answers5

14

I had the same problem. This is how I made it work in the new Django (trunk):

class MyModelAdmin(admin.ModelAdmin):
    # Your stuff here..

    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_staff: # condition
            self.exclude = ('field',)
        return super(PublishAdmin, self).get_form(request, obj=obj, **kwargs)

By overriding the get_form method and putting the logic here you can select which Form you want to have displayed. Above I have displayed the standard form when a condition was met.

Vikas Gulati
  • 968
  • 2
  • 10
  • 24
wunki
  • 653
  • 6
  • 13
  • 2
    Wow, of course, that makes sense. This is how I adapted it for my use: a) initialize `MyModelAdmin` with `exclude = []` (or whatever the base excludes are) and then do `self.exclude.append('field')` when conditions are met. – floer32 Sep 06 '12 at 14:10
  • Also just a note (that I couldn't edit because it was too small): `user.is_staff` is a property not a method, so calling it will throw an error. – floer32 Sep 06 '12 at 14:13
  • Shouldn't it be `obj=obj` as the second argument to the super class method call? – Vikas Gulati Jul 30 '14 at 13:47
7

As described in Creating forms from models - Selecting the fields to use, there are three ways:

  1. In the model, set editable=False. All forms created from the model will exclude the field.
  2. Define the fields attribute in the Meta inner class to only include the fields you want.
  3. Define the exclude attribute in the Meta inner class to list the fields you don't want.

So if your model has fields field1, field2, and field3 and you don't want field3, technique #2 would look like this:

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        fields = ('field1', 'field2')

And technique #3 would look like this:

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        exclude = ('field3',)
GabLeRoux
  • 16,715
  • 16
  • 63
  • 81
Selene
  • 1,917
  • 2
  • 13
  • 17
  • 4
    As i already wrote in my comment above, I have to remove fields dynamically, means, in the __init__-method. Therefore it's not possible to use the methods you suggested. – schneck Sep 24 '09 at 12:35
  • What do you mean by removing the fields "dynamically"? – Selene Sep 24 '09 at 17:08
  • 1
    @Selene: that means, that the fields that will be displayed (/validated/saved) are determined at runtime, not at design time – schneck Sep 24 '09 at 18:01
  • Okay, what are you actually trying to do that you need to change what fields are displayed at runtime? – Selene Sep 24 '09 at 19:57
  • 2
    In my project, there's a model containing many fields, and for the user, it's possible to select a subset of fields that he needs. That already works fine except the annoying problem in the admin backend. – schneck Sep 24 '09 at 20:28
3

This works great...

def __init__(self, instance, *args, **kwargs):    
    super(FormClass, self).__init__(instance=instance, *args, **kwargs)
    if instance and instance.item:
        del self.fields['field_for_item']
oak
  • 137
  • 8
  • AFAIK field_for_item will be set to none if it is missing in form.cleaned_data. Be careful: this could delete values in the db column field_for_item! – guettli Jun 28 '12 at 11:03
1

One cause I can think of is if your ModelAdmin class which uses your custom form has conflicting settings. For example if you have also explicitly specified 'name' field within 'fields' or 'fieldsets' of your ModelAdmin.

Botond Béres
  • 16,057
  • 2
  • 37
  • 50
0

You can use the exclude property to remove fields from a ModelForm

exclude = ('field_name1', 'field_name2,)
M. Ryan
  • 6,973
  • 11
  • 52
  • 76