2010-05-28 62 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