开发者

how to show a django ModelForm field as uneditable

taking my initial lessons with django ModelForm ,I w开发者_JAVA技巧anted to give the user ,ability to edit an entry in a blog.The BlogEntry has a date,postedTime, title and content.I want to show the user an editform which shows all these fields,but with only title and content as editable. The date and postedTime should be shown as uneditable.

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)

...

For adding an entry ,I use a ModelForm in the normal way..

class BlogEntryAddForm(ModelForm):
    class Meta:
        model = BlogEntry
...

But how do I create the edit form?I want it to show the date,postedTime as uneditable (but still show them on the form) and let the user edit the title and description.

if I use,exclude in class Meta for date and postedTime,that will cause them not to appear on the form.So,how can I show them as uneditable?

class BlogEntryEditForm(ModelForm):
    class Meta:
        model = BlogEntry
        ...?...


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

form.fields['field'].widget.attrs['readonly'] = True


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.


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', ))


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__'


From the documentation,

class BlogEntryEditForm(ModelForm):
    class Meta:
    model = BlogEntry
    readonly_fields = ['date','postedTime']
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜