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

Django表单中的奇怪行为(只读字段/小部件),django,django-models,django-forms,Django,Django Models,Django Forms,我正在编写一个测试应用程序来验证Django的一些功能,但它有问题。该测试应用程序是一个小型的“成绩册”应用程序,目前正在使用Alex Gaynor的只读字段功能 有两个问题可能是相关的。首先,当我在下面这两行上发表评论时: # myform = GradeForm(data=request.POST, instance=mygrade) myform = GradeROForm(data=request.POST, instance=mygrade) 它像我预期

我正在编写一个测试应用程序来验证Django的一些功能,但它有问题。该测试应用程序是一个小型的“成绩册”应用程序,目前正在使用Alex Gaynor的只读字段功能

有两个问题可能是相关的。首先,当我在下面这两行上发表评论时:

#        myform = GradeForm(data=request.POST, instance=mygrade)
        myform = GradeROForm(data=request.POST, instance=mygrade)
它像我预期的那样工作,当然除了学生领域是可变的

当注释以显示方式显示时,“studentId”字段显示为一个数字(不是名称,问题1),当我点击submit时,我得到一个错误,表示studentId需要是一个学生实例

我不知道如何解决这个问题。我不相信亚历克斯·盖诺的密码。任何代码都可以。我对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())
//模板

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

{{myform.as_table}}
//亚历克斯·盖诺密码

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
来自django导入表单的

从django.utils.html导入转义
从django.utils.safestring导入标记_safe
从django.forms.util导入flatatt
类ReadOnlyWidget(forms.Widget):
def呈现(自身、名称、值、属性):
final\u attrs=self.build\u attrs(attrs,name=name)
如果hasattr(self,“initial”):
值=自初始值
返回标记安全(“%s”%”(flatatt(最终属性)、转义(值)或“”)
def_已更改(自身、初始、数据):
返回错误
类ReadOnlyField(forms.FileField):
widget=ReadOnlyWidget
def uuu init uuuu(self,widget=None,label=None,initial=None,help\u text=None):
forms.Field.\uuuu init\uuuu(self,label=label,initial=initial,
帮助文本=帮助文本,小部件=小部件)
def清洁(自身、值、初始):
self.widget.initial=初始
返回首字母
Django 1.2(大约一周半前发布)支持开箱即用管理员的只读字段:


我不确定将新功能扩展到模型表单之类的东西以显示在您的站点上有多难,但它将比Alex(优秀但过时)的代码更具最新性。

不用担心ReadOnlyField。改用小部件

这是我经常使用的

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一起使用。

虽然我的代码最终会隐藏在用户登录页面后面,但我(还?)对使用管理系统的全部功能不感兴趣。ModelAdmin是否在通用管理框架之外可用?无论如何,我至少会看看django的代码,看看我是否可以“更新”Alex的代码以达到我的目的。我在这方面运气不太好。我觉得我用得不对。我不断得到“TypeError:\uuuu init\uuuuuu()正好接受3个参数(给定1个)”。我正在将ROForm中的studentId更改为“forms.CharField”,其中“widget=ReadOnlyWidget”应该是
模型选择字段,而不是CharField。但是使用Alex的小部件,而不是这个小部件,它的
\uuu init\uuu
方法中似乎有一些奇怪的要求。似乎许多“只读”解决方案都假定只读值是可选的,这可能是因为系统不存储/报告只读值。因为我的是必需的(它是学生ID),所以我在验证表单时出错。“此字段为必填字段”。这似乎是在调用自定义clean_field()例程之前发生的。我可能会将此作为另一个问题发布。