1

All my searching gave results for "custom fields" in Django which is not what I'm after, I'm trying to customize the Field class. The only similar question was not answered.


I'm building a form in Django, and I'm trying to specify a specific icon to appear by each input field. (See mockup)

For example, I have added a non-standard icon argument when building my form:

checkin.py

from django import forms

class CheckInForm(forms.Form):
    last_name = forms.CharField(
        icon="fa-id-card-o"
    )
    dob = forms.DateField(
        icon="fa-calendar"
    )
    ...

I would like to access this new icon argument from my template:

checkin.html

<form action="" method="post">
    {% csrf_token %}
    <table>
        {% for field in form %}
            <label for="{{ field.name }}" class="col-4 col-form-label">
                {{ field.label }}
            </label>
            <div class="col-8">
                <div class="input-group">
                    <div class="input-group-prepend">
                        <div class="input-group-text">
                            <i class="fa {{ field.icon }}"></i>   <!--- icon argument --->
                        </div>
                    </div>
                    {{ field }}
                </div>
            </div>
        {% endfor %}
    </table>
    <div class="form-group row">
        <div class="offset-4 col-8">
            <button name="submit" type="submit" class="btn btn-primary">Check In</button>
        </div>
    </div>
</form>

When I run this code, it of course fails with:

TypeError: init() got an unexpected keyword argument 'icon'

Attempted approach

It seems to me this is a good case to extend some Python classes.

Both CharField and DateField are subclasses of Django's Field class, so I thought I could extend it with something like this:

from django.forms import Field

class ExtendedField(Field):
    icon = ""

But this is where I get stuck: how do I deploy this new class? My CheckInForm object is a subclass of forms.Form, which is a subclass of BaseForm, which doesn't seem to directly create any Field objects -- so I'm not sure how they are related. However the Field class is used hundreds of times elsewhere. Should I override them all?

tl;dr: Is there an easier way to deploy this simple change to the Field class across every location it is used?

Allen Ellis
  • 269
  • 2
  • 9

1 Answers1

0

Quite dirty but straightforward solution:

from django import forms

class CustomCharField(forms.CharField):
    def __init__(self, *_, **kwargs):
        self.icon = kwargs.pop('icon', None)
        super().__init__(
            **kwargs
        )


class MyForm(forms.Form):
    title = CustomCharField(icon='dad', max_length=10)

In template get access by:

{{ form.title.field.icon}}
funnydman
  • 9,083
  • 4
  • 40
  • 55
  • Thanks! How could I access it from inside the loop? Your example code works (calling the field name individually), however this is an empty result: `{% for field in form %} {{ field.icon }} {% endfor %}` – Allen Ellis May 27 '20 at 15:32
  • It's is in the example: {% for field in form %} {{ field.field.icon }} {% endfor %} – funnydman May 27 '20 at 16:46
  • Thanks, your last comment fixed it! I upvoted you right away but I guess I don't have enough reputation yet to change visible scores. I appreciate your help! – Allen Ellis May 27 '20 at 19:17