6

I want to show a title and description from a db query in each form, but I don't want it to be in a charfield, I want it to be html-formatted text.

sample template code:

{% for form, data in zipped_data %}
   <div class="row">
      <div class="first_col">
         <span class="title">{{ data.0 }}</span>
         <div class="desc">
            {{ data.1|default:"None" }}
         </div>
      </div>
      {% for field in form %}
         <div class="fieldWrapper" style="float: left; ">
            {{ field.errors }}
            {{ field }}
         </div>
      {% endfor %}
{% endfor %}

Is this the most idiomatic way of doing this? Or, is there a way to add text that will not be displayed inside of a textarea or text input to my model:

class ReportForm(forms.Form):
   comment = forms.CharField()

?

S.Lott
  • 384,516
  • 81
  • 508
  • 779
Josh
  • 1,365
  • 3
  • 13
  • 23
  • I'm trying to add a title and description to each of the forms in the formset, but I don't know how to do that other than by adding form fields. I don't want to add more form fields because I don't want to title or description to appear in a text field, I want it to be plain or html-formatted text – Josh Feb 20 '09 at 17:39
  • I understand the templates, I'm talking about Django's form and formmset objects: http://docs.djangoproject.com/en/dev/topics/forms/formsets/ – Josh Feb 20 '09 at 17:46
  • It helps if you update the question rather than add comments. Please edit your question to add the new facts. – S.Lott Feb 20 '09 at 17:54
  • What does displaying text have to do with forms and formsets? Please clarify. – Brian Neal Feb 20 '09 at 17:57
  • I wanted to each form to have different text displayed next to its fields, both derived from a query. I managed to do this by zipping formset.forms with the associated tuples of text elements. Now in the template I manually write the text in each form. Is there a more idiomatic way of doing this? – Josh Feb 20 '09 at 18:05
  • Why don't you help us to help you by re-editing your question and posting some actual code for us to look at. – Brian Neal Feb 20 '09 at 20:50

4 Answers4

14

Instead of zipping your forms with the additional data, you can override the constructor on your form and hold your title/description as instance-level member variables. This is a bit more object-oriented and learning how to do this will help you solve other problems down the road such as dynamic choice fields.

class MyForm (forms.Form):
    def __init__ (self, title, desc, *args, **kwargs):
        self.title = title
        self.desc = desc
        super (MyForm, self).__init__ (*args, **kwargs) # call base class

Then in your view code:

form = MyForm ('Title A', 'Description A')

Adjust accordingly if you need these values to come from the database. Then in your template, you access the instance variables just like you do anything else, e.g.:

   <h1>{{ form.title }}</h1>
   <p>{{ form.desc }}</p>

From the way you phrased your question, I think you probably have some confusion around the way Django uses Python class attributes to provide a declarative form API versus instance-level attributes that you apply to individual instances of a class, in this case your form objects.

Community
  • 1
  • 1
Joe Holloway
  • 28,320
  • 15
  • 82
  • 92
  • No prob. Be sure to use the check mark for accepted solution so others can easily find the solution and to hand out some rep points. – Joe Holloway Feb 20 '09 at 22:05
6

I just created a read-only widget by subclassing the text input field one:

class ReadOnlyText(forms.TextInput):
  input_type = 'text'

  def render(self, name, value, attrs=None):
     if value is None: 
         value = ''
     return value

And:

class ReportForm(forms.Form):
  comment = forms.CharField(widget=ReadOnlyText, label='comment')
Andrei Taranchenko
  • 1,266
  • 1
  • 10
  • 22
2

I had to solve a similar problem and like your idea Andrei. I had some issues using it though, as, if there were validation errors, the value of the read-only field would get lost. To solve this, I did something similar but overrode HiddenInput instead and kept the value in a hidden form field. ie:

class ReadOnlyText(forms.HiddenInput):
    input_type = 'hidden'

    def render(self, name, value, attrs=None):
        if value is None:
            value = '' 
        return mark_safe(value + super(ReadOnlyTextWidget, self).render(name, value, attrs))

class ReportForm(forms.Form):
  comment = forms.CharField(widget=ReadOnlyText, label='comment')
Drew Volpe
  • 99
  • 3
  • It's unsafe. User can change content of hidden input and make you save some value in database. – Amaro Vita Jun 23 '18 at 14:20
  • @AmaroVita but there even is no database needed. It's only a form. If you have just a form field, the user can change anything he wants there. The backend does nothing with it, if you don't want. In this case, just don't use the "comment" value of the form in the form's `save()` method. – nerdoc Jun 20 '23 at 12:52
0

I think you can get it with "{{ field.value }}". Maybe it's the easier way.

{% for form in formset %}
    {% for field in form %}
        {% if forloop.counter = 1 %}
            <td><img src="{{ MEDIA_URL }}{{ field.value }}"/></td>
        {% endif %}
        {% if forloop.counter = 2 %}
            <td>{{ field.value }}</td>
        {% endif %}
        {% if forloop.counter > 2 %}
            <td>{{ field }}{{ field.errors }}</td>
        {% endif %} 
    {% endfor %}
{% endfor %}
Mörre
  • 5,699
  • 6
  • 38
  • 63