1

I have a python list

readonly = ['name', 'description']

that I wish to use in a few methods. However I get a global variable not defined error

class EditForm(ModelForm):
    # When editing form we want to disable multiple fields
    # Admin users can edit existing items via admin interface
    readonly = ['name', 'description']

    def __init__(self, *args, **kwargs):
        super(EditForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        for ro_field in readonly:
            if instance and instance.pk:
                self.fields[ro_field].widget.attrs['readonly'] = True

How do I keep the list local and be able to use it in the __init__ function and subsequent methods without repeating setting the list in each function

moadeep
  • 3,988
  • 10
  • 45
  • 72

2 Answers2

1

When you write the code as you did

class EditForm(ModelForm):
    # When editing form we want to disable multiple fields
    # Admin users can edit existing items via admin interface
    readonly = ['name', 'description']

    def __init__(self, *args, **kwargs):
        super(EditForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        for ro_field in readonly:
            if instance and instance.pk:
                self.fields[ro_field].widget.attrs['readonly'] = True

You are creating something that you would call a static variable. To acess it, you have to use the follow sintax

ClassName.variable

or self.variable

So, to access it, just do:

class EditForm(ModelForm):
    # When editing form we want to disable multiple fields
    # Admin users can edit existing items via admin interface
    readonly = ['name', 'description']

    def __init__(self, *args, **kwargs):
        super(EditForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        for ro_field in EditForm.readonly:
            if instance and instance.pk:
                self.fields[ro_field].widget.attrs['readonly'] = True

The difference between declaring

readonly = ['name', 'description']

And

self.readonly = ['name', 'description']

Is that the second case means the attribute belongs to the object you instantiated, so each object would have its own readonly list, and if you change it or whatever, you would have to change it for every object.

In the first case, the attribute belongs to the class, so it is equal in all objects.

rafaelc
  • 57,686
  • 15
  • 58
  • 82
  • 1
    You can also use `self.attr` to access class attributes from within instance methods (although if you *assign to* `self.attr`, you create an instance attribute that shadows the class attribute). – jonrsharpe Apr 17 '15 at 10:11
1

readonly is here an attribute of your EditForm class. You can access it either thru the class (EditForm.readonly) or - better - thru the instance itself:

class EditForm(ModelForm):
    # When editing form we want to disable multiple fields
    # Admin users can edit existing items via admin interface
    readonly = ['name', 'description']

    def __init__(self, *args, **kwargs):
        super(EditForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.pk:
            for ro_field in self.readonly:
                self.fields[ro_field].widget.attrs['readonly'] = True

It's better to access it thru the instance as it avoids hardcoding the class name into the method, and will better support inheritance (if you subclass EditForm and want to override readonly in your subclass).

Also I put the if instance and instance.pk test before the loop - no need to retest if for every iteration ;)

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118