Adding extra information to a form field and using it when rendering a django template

I want to add additional information for some django form fields and use it in templates to add additional HTML tags

I have a django form like:

class MyForm(forms.Form):
    integer = forms.IntegerField(
        help_text='Please enter your favorite integer number',
        label='Favorite integer',
        widget=forms.TextInput(attrs={'class':'input-xlarge'}))
    decimal = forms.DecimalField(
        min_value=Decimal('0.0001'),
        decimal_places=4,
        help_text='Please enter your favorite decimal number',
        label='Favorite decimal',
        widget=forms.TextInput(attrs={'class':'input-xlarge'}))
    ==> here I would like to say: decimal will have a new property

      

I am processing MyForm in a template using a loop over each field:

{% for item in form.visible_fields %}
  ==> here I would like to test if item has that property to add some html tags
  {{ item }}
{% endfor %}

      

I cannot use attrs widget as I want to use property information outside of the displayed input tag.

Should I create a custom field , write my own renderers for all the fields that I use, or is there a simpler solution I missed?


Edit: So far my solution is: (simplified version) Main template:

<form action="/somewhere/" method="post">{% csrf_token %}
 {% include 'form_field.html' with item=form.integer icon="icon-home" %}
 {% include 'form_field.html' with item=form.decimal icon="icon-list-alt" %}
 {% include 'form_field.html' with item=form.another icon="icon-signal" %}
 {% include 'form_field.html' with item=form.again   icon="icon-time" %}
 ...

      

In form_field.html, I create a field using Twitter Bootstrap input-preend div :

<div class="control-group">
  <label class="control-label" for="{{ item.name }}">{{ item.label }}</label>
  <div class="controls">
    {% if icon %}
      <div class="input-prepend">
      <span class="add-on"><i class="{{ icon }}"></i></span>
    {% endif %}
      {{ item }}
      <p class="help-block">{{ item.help_text }}</p>
    {% if icon %}
    </div>
    {% endif %}
  </div>
</div>

      

All I want is to simplify the main template by using a loop that lists all fields that are error prone. So I want to move this "icon-home" property from the template to the form definition so that I have all the attributes in the same place (certain attrs widgets are already on the form). Ideally, in the main template, I would:

{% for item in form.visible_fields %}
  {% include 'form_field.html' %}
{% endfor %}

      

I understand that this can be viewed as a misunderstanding of Django principles (the appearance of the site should be in templates, not in forms) ...

+3


source to share


3 answers


Custom form field + multiple inheritance + class that stores icon class name

First, let's define a class that captures the class name of the icon. We'll call it IconName:

class IconName(object):
    def get_icon_name(self):
        return self._icon_name
    def set_icon_name(self, value):
        self._icon_name = value
    icon_name = property(get_icon_name, set_icon_name)

      

You need to provide a custom field type for each form field type you are using. This is how it is done with IntegerField. Your custom fields class must inherit from the original django form field class (in this case IntegerField) and IconName class.

class CustomCharField(CharField, IconName):
    pass

      



After you have defined all the custom form field types your form requires, update their form. Then you need to initialize icon_name

for each form field on the form __init__()

:

def __init__(self, *args, **kwargs):
    super(forms.Form, self).__init__(*args, **kwargs)
    self.fields['integer'].icon_name = 'icon-home'
    ...

      

In a template, you can:

{% for item in form.visible_fields %}
<div class="control-group">
  <label class="control-label" for="{{ item.name }}">{{ item.label }}</label>
  <div class="controls">
    {% if item.field.icon_name %}
      <div class="input-prepend">
      <span class="add-on"><i class="{{ item.field.icon_name }}"></i></span>
    {% endif %}
      {{ item }}
      <p class="help-block">{{ item.help_text }}</p>
    {% if item.field.icon_name %}
    </div>
    {% endif %}
  </div>
</div>
{% endfor %}

      

I haven't tried this myself, but it should work (assuming I understand you correctly)

+5


source


Warning: I am just getting started with Python and Django.

See if this helps you get started:

class MyCustomTextInput(forms.widgets.TextInput):
    def render(self, name, value, attrs=None):
        original_html = super(MyCustomRender,self).render(name, value, attrs)
        icon_html = "<img src='/img.png' />"
        return "%s%s" % (icon_html,original_html)

class MyForm(ModelForm):
    myfield = MyCustomTextInput()

      



I believe this will produce an output similar to:

<img src='/img.png' /><input type="text" ... />

      

Take a look at https://github.com/django/django/blob/master/django/forms/widgets.py

0


source


Django ships by default with a simple renderer.

from django documentation :

<form action="/contact/" method="post">{% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Submit" />
</form>

      

As far as using a custom image, Javascript will be the solution if your form is dynamic. The form model is not, as it is just a view designed to efficiently create fomrs.

-1


source







All Articles