Create classes at runtnime

Ian ian.g.kelly at gmail.com
Fri Feb 4 17:56:48 EST 2011


On Feb 4, 2:32 pm, Peter Otten <__pete... at web.de> wrote:
> > (note: "...." means that the number of attributes can be variable)
>
> > class VirtualUserLimitForm(ModelForm):
> >     swap_limit = forms.CharField(max_length=100,
> > initial=monitor1.default_limit)
> >     memory_limit = forms.CharField(max_length=100,
> > initial=monitor2.default_limit)
> >     ...
>
> >     class Meta:
> >         model = model
>
> >     def __init__(self, *args, **kwargs):
> >         super(VirtualUserLimitForm, self).__init__(*args, **kwargs)
> >         if 'instance' in kwargs:
> >             self.fields['swap_limit'].initial =
> > kwargs['instance'].monitoring.filter(monitor=monitor1)[0].current
> >             self.fields['memory_limit'].initial =
> > kwargs['instance'].monitoring.filter(monitor=monitor2)[0].current
> >             ...
>
> > I can generate all the needed code as string and then use exec(), but
> > it seems ugly to me. I'm wondering if there is another way more
> > elegant to do that?  metaclasses maybe?
>
> The metaclass does indeed take a dictionary argument where you can provide
> class attributes, e. g.:
>
> >>> C = type("C", (), dict(a=1, b=lambda self: 42))
> >>> C().a, C().b()
>
> (1, 42)

This approach will basically work, but since you're subclassing the
Django ModelForm, note that it already has its own metaclass:

>>> django.forms.ModelForm.__class__
<class 'django.forms.models.ModelFormMetaclass'>

So you will need to either subclass ModelFormMetaclass for your
metaclass and override the __init__ method, or modify what Peter
posted like so:

>>> C = django.forms.ModelForm.__class__("VirtualUserLimitForm", (django.forms.ModelForm,), dict(a=1, b=lambda self: 42))

Cheers,
Ian



More information about the Python-list mailing list