5

How can i make a input read-only on a template, not in a model or view?

For example in

{% for form in formset %}
            {{ form.id }}
            <tr>
                <th>{{ form.project_name }}</th>

I need to make {{ form.project_name }} readonly(still as form), via html if it's possible(it has a default value in model.py)

Edit. I need it to be browser read only, not a form readonly.

Uasmi Nasser
  • 75
  • 1
  • 7
  • possible duplicate of [In a django form, How to make a field readonly (or disabled) so that it cannot be edited?](http://stackoverflow.com/questions/324477/in-a-django-form-how-to-make-a-field-readonly-or-disabled-so-that-it-cannot-b) – Two-Bit Alchemist Jun 04 '15 at 18:30
  • not quite actually, i need them to be disabled via html, like i can do with `` in html. – Uasmi Nasser Jun 04 '15 at 18:36
  • If you set readonly on the form it will do that for you, in addition to other protections if you read the top answer. – Two-Bit Alchemist Jun 04 '15 at 18:36

5 Answers5

15

If you want make all fields read only at a template level, use HTML <fieldset> disabled attribute:

    <form action="{% url "app.views.fonction" %}" method="post">{% csrf_token %}
        <h2>{% trans "Any title" %}</h2>
        <fieldset disabled="disabled">
            {{ form.as_ul }}
        </fieldset>
    <input type="submit" class="any" value="any" />
    </form>
Mr Lister
  • 45,515
  • 15
  • 108
  • 150
user3526918
  • 661
  • 6
  • 9
4

If you want to make input fields readonly in HTML, you'll have to write all the required HTML yourself.

HTML

<input type="text" value="{{ object.field_1 }}" readonly />
<input type="text" value="{{ object.field_2 }}" readonly />

<!-- And so on -->
xyres
  • 20,487
  • 3
  • 56
  • 85
3

There is a very nice answer here :

You can add the necessary html to the form field via the widget’s attributes property:

myform.fields['thefield'].widget.attrs['readonly'] = True

This way you can still write in your template

{{myform.thefield.label_tag}}
{{myform.thefield}}

and Django will put readonly="True" in the <input ...>.

Edouard Thiel
  • 5,878
  • 25
  • 33
1

The cleanest way is to create a new base form class that has a readonlyfields meta option, and does the rest of the work for you.

You shouldn't have any of that logic in the template, but rather validate data in the view, and put let django render readonly input as a span widget.

I use this in production with great success.

class SpanWidget(forms.Widget):
    '''Renders a value wrapped in a <span> tag.

    Requires use of specific form support. (see ReadonlyForm
    or ReadonlyModelForm)
    '''

    def render(self, name, value, attrs=None):
        final_attrs = self.build_attrs(attrs, name=name)
        return mark_safe(u'<span%s >%s</span>' % (
            forms.util.flatatt(final_attrs), self.display_value))

    def value_from_datadict(self, data, files, name):
        return self.original_value


class SpanField(forms.Field):
    '''A field which renders a value wrapped in a <span> tag.

    Requires use of specific form support. (see ReadonlyForm
    or ReadonlyModelForm)
    '''

    def __init__(self, *args, **kwargs):
        kwargs['widget'] = kwargs.get('widget', SpanWidget)
        super(SpanField, self).__init__(*args, **kwargs)
class Readonly(object):
    '''Base class for ReadonlyForm and ReadonlyModelForm which provides
    the meat of the features described in the docstings for those classes.
    '''

    class NewMeta:
        readonly = tuple()

    def __init__(self, *args, **kwargs):
        super(Readonly, self).__init__(*args, **kwargs)
        readonly = self.NewMeta.readonly
        if not readonly:
            return
        for name, field in self.fields.items():
            if name in readonly:
                field.widget = SpanWidget()
            elif not isinstance(field, SpanField):
                continue
            model_field = self.instance._meta.get_field_by_name(name)[0]
            field.widget.original_value = model_field.value_from_object(self.instance)
            field.widget.display_value = unicode(getattr(self.instance, name))


class ReadonlyForm(Readonly, forms.Form):
    '''A form which provides the ability to specify certain fields as
    readonly, meaning that they will display their value as text wrapped
    with a <span> tag. The user is unable to edit them, and they are
    protected from POST data insertion attacks.

    The recommended usage is to place a NewMeta inner class on the
    form, with a readonly attribute which is a list or tuple of fields,
    similar to the fields and exclude attributes on the Meta inner class.

        class MyForm(ReadonlyForm):
            foo = forms.TextField()
            class NewMeta:
                readonly = ('foo',)
    '''
    pass


class ReadonlyModelForm(Readonly, forms.ModelForm):
    '''A ModelForm which provides the ability to specify certain fields as
    readonly, meaning that they will display their value as text wrapped
    with a <span> tag. The user is unable to edit them, and they are
    protected from POST data insertion attacks.

    The recommended usage is to place a NewMeta inner class on the
    form, with a readonly attribute which is a list or tuple of fields,
    similar to the fields and exclude attributes on the Meta inner class.

        class Foo(models.Model):
            bar = models.CharField(max_length=24)

        class MyForm(ReadonlyModelForm):
            class Meta:
                model = Foo
            class NewMeta:
                readonly = ('bar',)
    '''
    pass

This is code I use in production:

class MembershipForm(ReadonlyModelForm):
    class Meta:
        model = Membership
        fields = ('user','board', 'privileged', 'alumni')

    class NewMeta:
        readonly = ('user')
    def email(self):
        return self.instance.user.email
Sebastian Wozny
  • 16,943
  • 7
  • 52
  • 69
0

I am using this simple code (part of a project using bootstrap) to render a read only form in a template (there is no submit button). This allows further template customization.

  <ul class="list-group">
     {% for field in form %} 
        <li class="list-group-item">
        {{ field.label_tag }} {{ field.value }}
        </li>
     {% endfor %}
  </ul>
mrtexaz
  • 663
  • 7
  • 22