How to get list of all fields from Django ModelForm

Somehow I had to cover the form with tests, all fields in TestCase should be set manually and updated by hands with every model change. I wanted to avoid this routine, solution should be simple --- grab the list of fields from the ModelForm and iterate over it. But there is a problem: by default, there is no way to get a list of fields considering that some of them are excluded or added to the form manually.

Solution

As a result of a short digging into the code of a ModelForm, I wrote the simple function that does exactly what I need, so I would like to share it here. Maybe it saves you a little time.

def get_all_fields_from_form(instance):
    """"
    Return names of all available fields from given Form instance.

    :arg instance: Form instance
    :returns list of field names
    :rtype: list
    """

    fields = []
    for item in instance.__dict__.items():
        if item[0] == 'declared_fields' or item[0] == 'base_fields':
            for field in item[1]:
                if hasattr(instance.Meta, 'exclude'):
                    if field not in instance.Meta.exclude:
                        fields.append(field)
                else:
                    fields.append(field)
    return fields

Improved solution

After I've posted this article on the Reddit, I've got the comment from Nicksil that makes me feel stupid, the function can be implemented much simpler:

def get_all_fields_from_form(instance):
    """"
    Return names of all available fields from given Form instance.

    :arg instance: Form instance
    :returns list of field names
    :rtype: list
    """

    fields = list(instance().base_fields)

    for field in list(instance().declared_fields):
        if field not in fields:
            fields.append(field)
    return fields

That's it!

Usage

# Let's create a simple model for the example
class ModelName(models.Model):
    field1 = models.DummyField()
    field2 = models.DummyField()
    field3 = models.DummyField()
    field4 = models.DummyField()


# And form for our model
class MyForm(ModelForm):
    class Meta:
       model = ModelName
       exclude = [field1, field2]


# Let's print-out the list of fields:
print(get_all_fields_from_form(MyForm))

# Output:
['field3', 'field4']
comments powered by Disqus