2

I am learning django form and want to know how to make a model form generated display only.

models.py

class Person(models.Model):
    first_name = models.CharField(max_length=40, null=True)
    last_name = models.CharField(max_length=40, null=True)
    #more fields

forms.py

class PersonForm(ModelForm):
    class Meta:
        model = Person

To generate a form with some existing data in the database:

person=Person.objects.get(id=someid)
person_form = PersonForm(instance = person)

All the fields in the form are editable in the page. However, I just want to display the data.

After some searching in StackOverflow I found a similar solution how to show a django ModelForm field as uneditable , which teaches how to set individual field uneidtable.

But I want to make the whole form uneditable. Is there any better way to do so instead of setting all the fields as uneditable one by one?

Thank you very much for your help.

Updates: I find the flowing code helps make the form uneditable, but still not sure whether this is the correct way to do it.

for field in person_form.fields:
            person_form.fields[field].widget.attrs['readonly'] = True

Thank you for giving your advice.

Community
  • 1
  • 1
Mona
  • 1,425
  • 6
  • 21
  • 31
  • 1
    This would be the way to do it as Django doesnt have a built-in widget for this. – Henrik Andersson Jul 08 '13 at 07:06
  • you mean the method in my updates? – Mona Jul 08 '13 at 07:11
  • @limelights yea, it works fine with most of the fields in my model, but there are CountryField in my model, seems that setting the 'readonly' to True does not work for the CountryField, it is still editable in the page. Is there any recommendation for this? – Mona Jul 08 '13 at 07:16
  • 1
    Why do you use Forms that are not editable? The idea of the forms is to submit data..? – Plamen Nikolov Jul 08 '13 at 09:00
  • @Pepi yea, I understand that. I use the ModelForm to input some data and save the data. Now I want to get the data and simply display them in the page...thought using the modelform to display model data is the good practise in django...so may i ask how this type of display is done in django generally? simple hints and answer would do, I'll go search and try to understand. Thanks – Mona Jul 08 '13 at 09:34
  • 1
    A good practice is to store user data in model via ModelForm. Best practice to show stored data is to use the model instance, not ModelForm instance :) – Plamen Nikolov Jul 09 '13 at 07:16
  • @Pepi thank you very much for your help. now I got this point. :) – Mona Jul 09 '13 at 07:39

4 Answers4

1

There is no attribute called editable or something similar on the form which can act on all the fields. So, you can't do this at form level.

Also, there is no such attribute on Field class used by django forms as well, so it wouldn't be possible to set such attribute and make the field read only. So, you will have to operate on on the fields of the form in __init__ of your form.

class PersonForm(ModelForm):
    class Meta:
        model = Person

    def __init__(self, *args, **kwargs):
        super(PersonForm, self).__init__(*args, **kwargs)
        for name, field in self.fields.iteritems():
            field.widget.attrs['readonly'] = 'true'

In case, you only want to make some fields uneditable, change the __init__.

    def __init__(self, *args, **kwargs):
        super(PersonForm, self).__init__(*args, **kwargs)
        uneditable_fields = ['first_name', 'last_name']
        for field in uneditable_fields:
            self.fields[field].widget.attrs['readonly'] = 'true'
Akshar Raaj
  • 14,231
  • 7
  • 51
  • 45
  • Does this mean that whenever a PersonForm form object is created, it would not be editable? – Mona Jul 08 '13 at 09:28
  • 1
    Yeah this will mean that all fields of PersonForm will be uneditable. Edited code in case you want to make only some fields as uneditable. – Akshar Raaj Jul 08 '13 at 09:39
1

Another solution perhaps, do not have to do any processing, just display like this..

<table border='1'>
    {% for field in form%}
        <tr>
            <td>{{field.label}}</td>
            <td>{{field.value}}</td>
        </tr>

    {% endfor%}

</table>
Mona
  • 1,425
  • 6
  • 21
  • 31
0

I know, old question, but since I had the same question this week it might help other people. This technique only works if you want the whole form to be readonly. It overrides any posted data (see def clean(self)) and sets the widget attributes to readonly.

Note: Setting the widget attributes to readonly does not prevent altering the model object instance.

class MyModelForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(MyModelForm, self).__init__(*args, **kwargs)

        if self.is_readonly():
            for k,f in self.fields.iteritems():
                f.widget.attrs['readonly'] = True

    def clean(self):
        if self.is_readonly():
                return {}
        return super(CompanyQuestionUpdateForm, self).clean()

    def is_readonly(self, question):
        if your_condition:
            return True
        return False

    class Meta:
        model = MyModel
Malte Jacobson
  • 215
  • 1
  • 11
0

It is possible to implement field widget to render bound ModelForm field values wrapped into div or td, sample implementation is there

https://github.com/Dmitri-Sintsov/django-jinja-knockout/blob/master/django_jinja_knockout/widgets.py

# Read-only widget for existing models.
class DisplayText(Widget):

Then a form metaclass can be implemented which will set field widget to DisplayText for all ModelForm fields automatically like that:

https://github.com/Dmitri-Sintsov/djk-sample/search?utf8=%E2%9C%93&q=DisplayModelMetaclass

class ClubDisplayForm(BootstrapModelForm, metaclass=DisplayModelMetaclass):

    class Meta(ClubForm.Meta):
        widgets = {
            'category': DisplayText()
        }

Feel free to use or to develop your own versions of widget / form metaclass.

There was discussion about read-only ModelForms at django bug ticket:

https://code.djangoproject.com/ticket/17031

closed as "Froms are for processing data, not rendering it."

But I believe that is mistake for these reasons:

  • ModelForms are not just processing data, they also map forms to models. Read-only mapping is the subset of mapping.

  • There are inline formsets and having read-only inline formsets is even more convenient, it leaves a lot of burden from rendering relations manually.

  • Class-based views can share common templates to display and to edit ModelForms. Thus read-only display ModelForms increase DRY (one of the key Django principles).

Dmitriy Sintsov
  • 3,821
  • 32
  • 20