Django: How to make a form with custom templating?

43,717

Solution 1

<form action="/contact/" method="post">
    {% for field in form %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }}: {{ field }}
        </div>
    {% endfor %}
    <p><input type="submit" value="Send message" /></p>
</form>

You can find the complete documentation here: http://docs.djangoproject.com/en/dev/topics/forms/#customizing-the-form-template

Solution 2

I don't think you need a formset here. Take a look here if you want a custom template for one view. If you want to create your own {{ form.as_foobar }}, just subclass forms.Form, something like this:

class MyForm(forms.Form):
  def as_foobar(self):
    return self._html_output(
      normal_row = u'%(label)s %(field)s%(help_text)s',
      error_row = u'%s',
      row_ender = '',
      help_text_html = u' %s',
      errors_on_separate_row = False)

and just use it in your forms.py:

class ContactForm(MyForm):
  # ..

Solution 3

For whoever needs the <table> version of jbcurtin's answer:

<form method="post">{% csrf_token %}
  <table>
    {% for field in form %}
      <tr>
        <th>{{field.label_tag}}</th>
        <td>
          {{ field.errors }}
          {{ field }}
        </td>
      </tr>
    {% endfor %}
  </table>
  <hr/>
  <input type="submit" value="Conferma" />
</form>

Solution 4

Looks like you might be interested in django-floppyforms (docs), which gives you much more control over field rendering.

Share:
43,717

Related videos on Youtube

Nick Heiner
Author by

Nick Heiner

JS enthusiast by day, horse mask enthusiast by night. Talks I've Done

Updated on July 09, 2022

Comments

  • Nick Heiner
    Nick Heiner almost 2 years

    I have a model:

    class Setting(models.Model):
    
        class Meta:
            abstract = True
    
        name = models.CharField(max_length=120, primary_key=True)
        description = models.CharField(max_length=300, blank=True)
    
    class IntegerSetting(Setting):
        value = models.IntegerField()
    

    I would like to create a form that looks something like:

    <form method="POST" action="">
         {% for model in models %}
         <label>{{model.name}}</label> <input value='{{model.value}}' />
         <p>{{model.description}}</p>
         {% endfor %}
    </form>
    

    I'm not quite sure how to go about doing this. Perhaps I need to use a formset?

    from django.forms.models import modelformset_factory
    from apps.about.models import Setting, IntegerSetting
    
    def site_settings(request):
        formset = modelformset_factory(IntegerSetting)()
    
        return render_to_response("about/admin/site-settings.html", {'formset': formset}, RequestContext(request, {}))
    

    Then in the template, I'd want to render the form differently than default. I'm not quite sure how to go about accessing the model properties, however. Is this the right approach, or is there another way I should be going about doing this?

    Update: This is what I'm currently doing. It renders exactly as I'd like it to, aside from the styling. However, I feel that it's deeply hacky:

    class SettingsForm(ModelForm):
        class Meta:
            model = IntegerSetting
    
        def as_table(self):
            bound_field = BoundField(self, self.fields['value'], 'value')
            return mark_safe("<tr><td><label>%s</label></td><td>%s\n<p class='help'>%s</p></td></tr>" % (self.instance.name,
                                                                           self.instance.description, 
                                                                           bound_field.__unicode__())) 
    
    def edit_settings(request):
        forms = [SettingsForm(instance=intSetting) for intSetting in IntegerSetting.objects.all()]
    
        return render_to_response("admin/edit-settings.html", {'forms': forms}, RequestContext(request, {}))
    

    edit-settings.html:

    {% extends "admin/base_site.html" %}
    {% block title %}System Settings{% endblock %}
    
    {% block content %}
        <form method="post" action="">
            <table>
            {% for form in forms %}
            {{form}}
            {% endfor %}
            </table>
        </form>
    {% endblock %}
    

    Is there a better approach to this?

    Also, I'm not sure if I'll encounter problems when the form is submitted or not.

  • SashaN
    SashaN about 13 years
    Also I don't see to the point of using formsets. Doing something like this: from django.forms import ModelForm class IntegerSettingForm(ModelForm): class Meta: model = IntegerSetting should create a IntegerSettingForm class, which you can use to create your form instances in views.
  • Nick Heiner
    Nick Heiner about 13 years
    This prints all the fields, but I want to use the value of one field as a label, and only have one field actually be an input.
  • Nick Heiner
    Nick Heiner about 13 years
    The documentation you attached was useful, but it didn't mention a field attribute to print the value, not the widget. That's what I really want.
  • Nick Heiner
    Nick Heiner about 13 years
    And how would I get the results of as_foobar in the template?
  • Nick Heiner
    Nick Heiner about 13 years
    Also, this is specifying the output on a field level, right? What I need is: "Model.name.value: Model.value.value (Model.description.value)"
  • jbcurtin
    jbcurtin about 13 years
    If you don't want the value to be editable, set 'editable' to false on the model and the form field will pick up on this.
  • Apollo Data
    Apollo Data over 7 years
    You'd use {{ form.as_foobar }} (similar to form.as_p) in the template. Replace 'form' with whatever your form variable is called.