开发者

Odd behavior in Django Form (readonly field/widget)

开发者 https://www.devze.com 2023-01-02 00:46 出处:网络
I\'m having a problem with a test app I\'m writing to verify some Django functionality. The test app is a small \"grade book\" application that is currently using Alex Gaynor\'s readonly field functio

I'm having a problem with a test app I'm writing to verify some Django functionality. The test app is a small "grade book" application that is currently using Alex Gaynor's readonly field functionality http://lazypython.blogspot.com/2008/12/building-read-only-field-in-django.html

There are 2 problems which may be related. First, when I flop the comment on these 2 lines below:

#        myform = GradeForm(data=request.POST, instance=mygrade)
        myform = GradeROForm(data=request.POST, instance=mygrade)

it works like I expect, except of course that the student field is changeable.

When the comments are the shown way, the "studentId" field is displayed as a number (not the name, problem 1) and when I hit submit I get an error saying that studentId needs to be a Student instance.

I'm at a loss as to how to fix this. I'm not wedded to Alex Gaynor's code. ANY code will work. I'm relatively new to both Python and Django, so the hints I've seen on websites that say "m开发者_StackOverflowaking a read-only field is easy" are still beyond me.

// models.py

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)

# testbed.grades.readonly is alex gaynor's code
from testbed.grades.readonly import ReadOnlyField
class GradeROForm(ModelForm):
    studentId = ReadOnlyField()
    class Meta:
        model=Grade

class GradeForm(ModelForm):
    class Meta:
        model=Grade

// views.py

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

// template

<p>{{ info }}</p>
<form method="POST" action="">
<table>
{{ myform.as_table }}
</table>
<input type="submit" value="Submit">
</form>

// Alex Gaynor's code

from django import forms
from django.utils.html import escape
from django.utils.safestring import mark_safe

from django.forms.util import flatatt
class ReadOnlyWidget(forms.Widget):
    def render(self, name, value, attrs):
        final_attrs = self.build_attrs(attrs, name=name)
        if hasattr(self, 'initial'):
            value = self.initial
        return mark_safe("<span %s>%s</span>" % (flatatt(final_attrs), escape(value) or ''))

    def _has_changed(self, initial, data):
        return False

class ReadOnlyField(forms.FileField):
    widget = ReadOnlyWidget
    def __init__(self, widget=None, label=None, initial=None, help_text=None):
        forms.Field.__init__(self, label=label, initial=initial, 
            help_text=help_text, widget=widget)

    def clean(self, value, initial):
        self.widget.initial = initial
        return initial


Don't bother with the ReadOnlyField. Use the Widget instead.

Here is the one I use regularly.

class ReadOnlyWidget(forms.Widget):

    def __init__(self, original_value, display_value):
        self.original_value = original_value
        self.display_value = display_value
        super(ReadOnlyWidget, self).__init__()

    def _has_changed(self, initial, data):
        return False

    def render(self, name, value, attrs=None):
        if self.display_value is not None:
            return unicode(self.display_value)
        return unicode(self.original_value)

    def value_from_datadict(self, data, files, name):
        return self.original_value

Use it with CharField.


Django 1.2 (released about a week and a half ago) supports read-only fields for the admin out of the box:

http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields

I'm not sure how hard it is to extend that new functionality into something like a ModelForm to be displayed on your site, but it would serve as a more up-to-date starting point than Alex's (excellent but dated) code.

0

精彩评论

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