0

I'm writing a mixin class to dynamically add extra fields to a ModelForm which sublasses it.

The new fields are generated in the mixin's __init__ method. See bellow:

mixin class code (strongly shortened & simplified):

class ForeignFieldsMixin(object):
    # …
    def __init__(self, *args, **kwargs):
        # …
        instance = kwargs.get('instance')
        self.fields[extra_field_name] = fields_for_model(fmodel, (fldname,))
        # ^^^^^^ here a new field instance is added
        self.fields[extra_field_name].initial = 'some value'
        # ^^^^^^ here is set an inital value for the new field 
        # …

However form's class still refuses to list the new field name in its Meta.fields:

class ContactAdminForm(ForeignFieldsMixin, forms.ModelForm):
    # …
    class Meta:
        model   = Contact
        fields  = ('title', 'extra_field_name',)

and fails with the following exception

File "../lib/python2.7/site-packages/django/forms/models.py", line 215, in __new__
    raise FieldError(message)
FieldError: Unknown field(s) (extra_field_name) specified for Contact

I do suspect ModelForm's metaclass (or of some of its ancestors) at the time of class definition ie. before classes are instantiated raises this exception as it not yet knows about new field names added.

I do not know if I'm taking this from the wrong side as the documentation is rather sparse in this area. I would really like avoid monkey-patching of ModelForm's metaclass.

Is there some other way how to simulate the basic in-code fields definition to satisfy Django's class model with its metaclasses protectors but do it dynamically with a generally applicable class/function ?

David Unric
  • 7,421
  • 1
  • 37
  • 65
  • I don't see where you define 'extra_field_name' var in your __init__ method. Also, you should probably call super on the init method of the form class that's derived from it - super(ForeignFieldsMixin, self).__init__(*args, **kwargs) – Esteban Jun 24 '14 at 16:46
  • I do call `super`, don't worry. `extra_field_name` is generated on the fly but it does not matter. This example how the new fields are generally created. – David Unric Jun 24 '14 at 17:40

1 Answers1

0

You don't want or need to specify your extra fields in the fields tuple. You're adding them manually in the __init__, so putting them in fields is irrelevant.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • So how can a set the extra fields to be used in a form ? In addition I'd like to be placed at specified place, like between original fields. Now the form is rendered but added extra fields are missing. – David Unric Jun 24 '14 at 17:39
  • You do it by adding Field instances to `self.fields`. Although I don't understand what you're trying to do with `fields_for_model`: each entry in self.fields is supposed to be an actual Field, not a dict of fields which is what's returned by that function. And ordering is irrelevant: it sounds like you're outputting your form with `form.as_p`, which is really just a quick prototyping tool and shouldn't really be used in proper code. Specify your fields individually in the template. – Daniel Roseman Jun 24 '14 at 17:50
  • Thanks for the anwser. I can check form's `self.fields` does contain the new field and is set to intial value however still missing in a form. Form *does not have a template* as it gets generated when assigned to a `django.contrib.admin.options.ModelAdmin` and registered with `admin.site.register`. Loosing ideas here. Thanks for your time. – David Unric Jun 24 '14 at 18:41
  • I'm trying to use `django.forms.models.fields_for_model` function to get `Field` instance as a generic way to retrieve selected existing fields of related foreign model. – David Unric Jun 24 '14 at 18:50