3

I'm writing a test "grade book" application. The models.py file is shown below.

class Student(models.Model):
    name = models.CharField(max_length=50)
    parent = models.CharField(max_length=50)
    def __unicode__(self):
        return self.name

class Grade(models.Model):
    studentId = models.ForeignKey(Student)
    finalGrade = models.CharField(max_length=3)

I'd like to be able to change the final grade for several students in a modelformset but for now I'm just trying one student at a time. I'm also trying to create a form for it that shows the student name as a field that can not be changed, the only thing that can be changed here is the finalGrade. So I used this trick to make the studentId read-only.

class GradeROForm(ModelForm):
    studentId = forms.ModelChoiceField(queryset=Student.objects.all())
    def __init__(self, *args, **kwargs):
        super(GradeROForm,self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.id:
            self.fields['studentId'].widget.attrs['disabled']='disabled'
    def clean_studentId(self):
        instance = getattr(self,'instance',None)
        if instance:
            return instance.studentId
        else:
            return self.cleaned_data.get('studentId',None)
    class Meta:
        model=Grade

And here is my view:

def modifyGrade(request,student):
    student = Student.objects.get(name=student)
    mygrade = Grade.objects.get(studentId=student)
    if request.method == "POST":
        myform = GradeROForm(data=request.POST, instance=mygrade)
        if myform.is_valid():
            grade = myform.save()
            info = "successfully updated %s" % grade.studentId
    else:
        myform=GradeROForm(instance=mygrade)
    return render_to_response('grades/modifyGrade.html',locals())

This displays the form like I expect, but when I hit "submit" I get a form validation error for the student field telling me this field is required. I'm guessing that, since the field is "disabled", the value is not being reported in the POST and for reasons unknown to me the instance isn't being used in its place.

I'm a new Django/Python programmer, but quite experienced in other languages. I can't believe I've stumbled upon such a difficult to solve problem in my first significant django app. I figure I must be missing something. Any ideas?

oz123
  • 27,559
  • 27
  • 125
  • 187
jamida
  • 2,869
  • 5
  • 25
  • 22
  • Have a look at the answers in ["In a django form, How to make a field readonly (or disabled) so that it cannot be edited?"](http://stackoverflow.com/questions/324477/in-a-django-form-how-to-make-a-field-readonly-or-disabled-so-that-it-cannot-be) I think with those you will be able to solve your problem. – Felix Kling May 29 '10 at 02:17
  • Thanks Felix. I saw that before and couldn't get it to work right. See my comment below regarding adding "required=False" which seems to have been the final hurdle. – jamida May 29 '10 at 17:15

1 Answers1

6

You should perform:

self.fields['studentId'].widget.attrs['readonly'] = True

and also make sure not to overwrite the value on postback.

Furthermore, if still having problems with the required field, you can do the following in your modelform:

studentID = forms.CharField(label="A label", help_text="Student ID", required=False)
Martin Eve
  • 2,703
  • 1
  • 23
  • 23
  • 1
    That did the trick! Seems ugly, but workable. This is a prototype anyway. I'm surprised by one thing though. I had to add "required=False" even though this is in fact a required field in the model level. The studentId field is not being sent back in the POST response, and w/o the "required=False" statement form validation fails BEFORE my customized Clean routine. But apparently with "required=false" my Clean routine has a chance to run and reset the proper studentId info. – jamida May 29 '10 at 17:15
  • Actually there's one small problem remaining. After I submit the form when it returns the "readonly field" is blank. It still works, probably because of the modified clean() but it's awkward. Any thoughts? – jamida May 29 '10 at 20:09
  • Can you repopulate the form value from the retrieved model, perhaps? – Martin Eve May 30 '10 at 10:33