2010-05-28 79 views
4

我正在写一个测试应用程序的问题,以验证某些Django功能。该测试应用程序是目前使用Alex Gaynor的只读字段功能的小型“等级书”应用程序。http://lazypython.blogspot.com/2008/12/building-read-only-field-in-django.htmlDjango窗体中的奇怪行为(只读字段/窗口小部件)

有两个可能相关的问题。首先,当我翻牌下面这两条线的评论:

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

它像我期望的那样,当然除了学生场是多变的。

当评论是显示的方式,“studentId”字段显示为一个数字(不是名称,问题1),当我点击提交时,我得到一个错误,说studentId需要是一个学生实例。

我不知道如何解决这个问题。我并不喜欢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()) 

//模板

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

//亚历克斯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 

回答

3

的Django 1.2(发行了约一周半前)支持只读管理员场开箱:

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

我不知道有多难,以便扩展新功能转换成类似于ModelForm的内容以显示在您的网站上,但它将作为比Alex(优秀但过时)代码更新的起点。

+0

虽然我的代码最终会落在用户登录页面后面,但我还没有(对?)有兴趣使用管理系统的全部功能。 ModelAdmin是否可以在一般管理框架之外使用?无论如何,我至少会在那里查看django的代码,看看我是否可以为我的目的“更新”Alex的代码。 – jamida 2010-05-28 19:56:26

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

+0

我没有太多运气。我不认为我正确使用它。我一直得到“TypeError:__init __()只需要3个参数(给出1)”。我将ROForm中的studentId更改为“forms.CharField”,并带有“widget = ReadOnlyWidget” – jamida 2010-05-28 20:17:31

+1

应该是'ModelChoiceField',而不是CharField。但是使用Alex的小部件而不是这个,它似乎在'__init__'方法中有一些奇怪的要求。 – 2010-05-28 20:31:04

+0

我遇到的一个问题是我试图用“强制性”字段来做到这一点。看起来,许多“只读”解决方案假定只读值是可选的,可能是因为系统不存储/报告只读值。由于我是必需的(这是学生证),所以在验证表单时出现错误。“这是必填栏”。这似乎是在调用自定义clean_field()例程之前发生的。我可能会将此作为一个不同的问题发布。 – jamida 2010-05-28 23:56:08

相关问题