views:

28

answers:

2

I have model form and I need to have one of the fields be read only until after it's saved. I haven't figured out a good way to do this, and below is what I have in my admin.py.

class RequestForm(forms.ModelForm):
    trac = forms.URLField(min_length=400, required=False)
    impacted_users = forms.ModelMultipleChoiceField(queryset=Group.objects.all(), widget=forms.CheckboxSelectMultiple)
    formfield_overrides = {
    }

    class Meta:
        model = Request

class RequestAdmin(admin.ModelAdmin):
    form = RequestForm
    list_display = ['id', 'title', 'priority', 'requestor', 'status']
    list_filter = ['requestor', 'priority', 'impacted_users']
    actions = [complete]

    class Media:
        js = (
            '/media/js/jquery.js',
            '/media/js/hide.js',
            )

    def save_model(self, request, obj, form, change):
        instance = form.save(commit=False)
        instance.requestor = request.user
        instance.save()
        form.save_m2m()
        return instance
A: 

This would have to be done in the controller (called View in Django).

In the view handling your form, check for a line like that :

if request.method == 'POST':
    ...
else:
    ...

This should look like the view of the official documentation. (There should also be a test to check if form.is_valid() in the first part of this if.)

The first part of this logical bloc is executed whenever it is not the first time the user loads the form (ie. invalid entries). The second part, the else, is what happens when the form is loaded for the first time.

You can check to manipulate the form widget in the according section of this logical bloc. Refer to this post to set an input field read only. You should be able to modify your form class at this point.

Soravux
I haven't implemented any views yet, I was hoping I could do this in the admin, since it will be mainly administrators looking at this. Looks like it's time to leave the admin behind :)
Ryan
+1  A: 

Let's say the field in question is special_field.

Here's how you'd do it (from this related answer):

class RequestForm(forms.ModelForm):
    trac = forms.URLField(min_length=400, required=False)
    impacted_users = forms.ModelMultipleChoiceField(queryset=Group.objects.all(), widget=forms.CheckboxSelectMultiple)
    formfield_overrides = {
    }

    def __init__(self, special_field_starting_value=None, *args, **kwargs):
        super(RequestForm,self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if not (instance and instance.id):
            self.fields['special_field'].widget.attrs['readonly'] = True
            self.fields['special_field'].initial = special_field_starting_value

    class Meta:
        model = Request

This will work in both admin and in a normal view.

Full disclosure: actually, I haven't tested it, but assuming the answer I linked to is still valid, then the code I wrote based on this should also be valid.

Jordan Reiter