[Django]-How to show a django ModelForm field as uneditable

15๐Ÿ‘

โœ…

In the form object, declare the attribute of the field as readonly:

form.fields['field'].widget.attrs['readonly'] = True
๐Ÿ‘คdusual

3๐Ÿ‘

Is date field represent a date when the entry first created or when it was modified last time? If first then use auto_now_add option else use auto_now. That is:

date = models.DateField(auto_now_add=True)

will set date to now when entry will be created.

auto_now_add makes field uneditable. For other cases use editable option to make any field uneditable. For example

postedDate = models.TimeField(null=True, editable=False)

Also, likely you will add posted boolean field to Entry model, so it is convinient to set auto_now on postedDate. It will set postedDate to now every time you modify a Entry including one when you set posted to True.

๐Ÿ‘คKirill

0๐Ÿ‘

I implemented it this way: https://djangosnippets.org/snippets/10514/
this implementation uses the data of model instance for all read-only fields and not the data obtained while processing the form

below the same code but using his example

from __future__ import unicode_literals

from django.utils import six
from django.utils.encoding import force_str

__all__ = (
    'ReadOnlyFieldsMixin',
    'new_readonly_form_class'
)


class ReadOnlyFieldsMixin(object):
    """Usage:
    class MyFormAllFieldsReadOnly(ReadOnlyFieldsMixin, forms.Form):
        ...


    class MyFormSelectedFieldsReadOnly(ReadOnlyFieldsMixin, forms.Form):
        readonly_fields = ('field1', 'field2')
        ...
    """
    readonly_fields = ()

    def __init__(self, *args, **kwargs):
        super(ReadOnlyFieldsMixin, self).__init__(*args, **kwargs)
        self.define_readonly_fields(self.fields)

    def clean(self):
        cleaned_data = super(ReadOnlyFieldsMixin, self).clean()

        for field_name, field in six.iteritems(self.fields):
            if self._must_be_readonly(field_name):
                cleaned_data[field_name] = getattr(self.instance, field_name)

        return cleaned_data

    def define_readonly_fields(self, field_list):

        fields = [field for field_name, field in six.iteritems(field_list)
                  if self._must_be_readonly(field_name)]

        map(lambda field: self._set_readonly(field), fields)

    def _all_fields(self):
        return not bool(self.readonly_fields)

    def _set_readonly(self, field):
        field.widget.attrs['disabled'] = 'true'
        field.required = False

    def _must_be_readonly(self, field_name):
        return field_name in self.readonly_fields or self._all_fields()


def new_readonly_form_class(form_class, readonly_fields=()):
    name = force_str("ReadOnly{}".format(form_class.__name__))
    class_fields = {'readonly_fields': readonly_fields}
    return type(name, (ReadOnlyFieldsMixin, form_class), class_fields)

Usage:

class BlogEntry(models.Model):
    title = models.CharField(unique=True,max_length=50)
    description = models.TextField(blank=True)
    date = models.DateField(default=datetime.date.today)
    postedTime = models.TimeField(null=True)


# all fields are readonly    
class BlogEntryReadOnlyForm(ReadOnlyFieldsMixin, forms.ModelForm):
    class Meta:
        model = BlogEntry

# selected fields are readonly
class BlogEntryReadOnlyForm2(ReadOnlyFieldsMixin, forms.ModelForm):
    readonly_fields = ('date', 'postedTime')
    class Meta:
        model = BlogEntry

or use the function

class BlogEntryForm(forms.ModelForm):
    class Meta:
        model = BlogEntry

BlogEntryFormReadOnlyForm = new_readonly_form_class(BlogEntryForm, readonly_fields=('description', ))

0๐Ÿ‘

This will prevent any user from hacking the request:

self.fields['is_admin'].disabled = True

Custom form example:

class MemberShipInlineForm(forms.ModelForm):
    is_admin = forms.BooleanField(required=False)

    def __init__(self, *args, **kwargs):

        super(MemberShipInlineForm, self).__init__(*args, **kwargs)

        if 'instance' in kwargs and kwargs['instance'].is_group_creator:
            self.fields['is_admin'].disabled = True

    class Meta:
        model = MemberShip
        fields = '__all__'
๐Ÿ‘คxleon

-4๐Ÿ‘

From the documentation,

class BlogEntryEditForm(ModelForm):
    class Meta:
    model = BlogEntry
    readonly_fields = ['date','postedTime']
๐Ÿ‘คlprsd

Leave a comment