Sweet Girl
Sweet Girl

Reputation: 21

How to map model fields with form field in Django

We have one application containing models.py which contains n no. of classes that inherits base class.We want to create form which dynamically takes value from user n saves in db but problem is that we want to use django form fields instead of django model forms.

As we know there are some fields missing in django forms such as PositiveIntegerField, CommaSeparetedIntegerFields etc. How can we achieve this using django form fields?
If we write follwing code in shell.

from djnago.db import models
mvar = models.PositiveIntegerFields()

from django import forms
fvar = forms.PositiveIntegerFields()
AttributeError: 'module' object has no attribute 'PositiveIntegerField'

forms.py

from django import forms

class ContextForm(forms.Form):
    def __init__(self, rdict, *args, **kwargs):
        super(ContextForm, self).__init__(*args, **kwargs)
        for key in rdict.keys():
            self.fields['%s' % str(key)] = getattr(forms,rdict.get(key))()

rdict = {'address': 'CharField','phone': 'CharField', 'Salary': 'PositiveIntegerField','first name': 'CharField','last name':'CharField'}

Upvotes: 2

Views: 5195

Answers (1)

Looking at the source, all the field does is call the default form field with a keyword argument: min_value.

class PositiveIntegerField(IntegerField):
    description = _("Positive integer")

    def get_internal_type(self):
        return "PositiveIntegerField"

    def formfield(self, **kwargs):
        defaults = {'min_value': 0}
        defaults.update(kwargs)
        return super(PositiveIntegerField, self).formfield(**defaults)

Therefore what you are looking for is merely

from django import forms
fvar = forms.IntegerField(min_value=0)
fvar.clean(-1)
# ValidationError: [u'Ensure this value is greater than or equal to 0.']

As for CommaSeparatedIntegerField, it looks like a CharField with some django.core.validators.validate_comma_separated_integer_list passed in.

f = forms.CharField(validators=[django.core.validators.validate_comma_separated_integer_list])
f.clean('1,2,3')

All this does is make sure the passed in string is '^[\d,]+$'. The field doesn't even do any python conversions... it doesn't really seem to save much time if just validates form input. Indeed, there's a comment that says "maybe move to contrib". Agreed..


Decided to look into this for fun. Here's a ModelForm generator that overrides model fields with new fields... It doesn't yet handle kwargs. It was just the first method I could think of to do this.. without looking into modelform generation itself. It constructs a regular ModelForm that modifies the form /after/ initialization.

MODEL_FIELD_MAP = {
    models.IntegerField: forms.CharField, 
    # change all IntegerField to forms.CharField
}

def modelform_generator(mymodel):
    class MyModelForm(forms.ModelForm):
        class Meta:
            model = mymodel
        def __init__(self, *args, **kwargs):
            super(MyModelForm, self).__init__(*args, **kwargs)
            for name, form_field in self.fields.items():
                try:
                    model_field = self._meta.model._meta.get_field_by_name(name)[0]
                    # is this a model field?

                    field_override = MODEL_FIELD_MAP.get(model_field.__class__)
                    # do we have this model field mapped to a form field?

                    if field_override:
                        self.fields[name] = field_override()
                        # set the form field to the target field class

                except models.FieldDoesNotExist:
                    pass
    return MyModelForm

Upvotes: 1

Related Questions