Django Form中的奇怪行为(只读字段/小部件)

时间:2010-05-28 19:21:42

标签: django django-models django-forms

我正在编写测试应用程序的问题,我正在编写以验证一些Django功能。测试应用程序是一个小型“成绩簿”应用程序,目前正在使用Alex Gaynor的只读字段功能http://lazypython.blogspot.com/2008/12/building-read-only-field-in-django.html

有两个可能相关的问题。首先,当我在下面的这两行中翻转评论时:

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

它的工作方式与我预期的一样,当然除了学生领域是可变的。

当评论以显示的方式显示时,“studentId”字段显示为数字(不是名称,问题1),当我点击提交时,我收到一条错误消息,指出studentId需要是Student实例。

我对如何解决这个问题感到很茫然。我并不喜欢Alex Gaynor的代码。任何代码都可以。我对Python和Django都比较陌生,所以我在网站上看到的“制作只读字段很容易”的提示仍然超出了我的范围。

// 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的代码

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

2 个答案:

答案 0 :(得分:5)

不要打扰ReadOnlyField。改为使用Widget。

这是我经常使用的那个。

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

将它与CharField一起使用。

答案 1 :(得分:3)

Django 1.2(大约一周半前发布)支持开箱即用的管理员的只读字段:

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

我不确定将新功能扩展到您的网站上显示的ModelForm是多么困难,但它可以作为一个比Alex更新的起点(优秀但过时)代码。