2009-12-01 7 views
15

Mein Formularfeld sieht in etwa wie folgt aus:Django ein Formularfeld erstellen, die nur Widgets verwenden gelesen hat

class FooForm(ModelForm): 
    somefield = models.CharField(
     widget=forms.TextInput(attrs={'readonly':'readonly'}) 
    ) 

    class Meta: 
     model = Foo 

einen Fehler wie die folgenden mit dem Code Geting oben: init() wurde ein unerwartetes Schlüsselwort-Argument 'Widget'

Ich dachte, das ist eine legitime Verwendung eines Formular-Widget?

+0

Das in django geändert 1,9 https://stackoverflow.com/questions/324477/in-a-django-form-how -do-i-make-a-field-readonly-oder-deaktiviert-so-dass-es-kann nicht – zudebluvstein

Antwort

40

Sie sollten ein Formularfeld verwenden und kein Modellfeld:

somefield = models.CharField(
    widget=forms.TextInput(attrs={'readonly':'readonly'}) 
) 

ersetzt mit

somefield = forms.CharField(
    widget=forms.TextInput(attrs={'readonly':'readonly'}) 
) 

Sollte es beheben.

+1

Das sieht unsicher aus! – jpic

+0

Um jpic Punkt, Benutzer einfach deaktivieren Sie die Readonly-Flag und noch Informationen senden. Eine umfassendere Antwort finden Sie unter http://stackoverflow.com/a/325038/4972. –

17

Beachten Sie, dass das Attribut readonly Django nicht daran hindert, einen vom Client gesendeten Wert zu verarbeiten. Wenn es für Sie wichtig ist, dass sich der Wert nicht ändert, egal wie kreativ Ihre Benutzer mit FireBug sind, müssen Sie eine kompliziertere Methode verwenden, z. a ReadOnlyField/ReadOnlyWidget wie in einer blog entry von Alex Gaynor demonstriert.

1

Wie Benjamin (https://stackoverflow.com/a/2359167/565525) gut erklärt, zusätzlich zum Rendern richtig, müssen Sie Feld auf Backend richtig verarbeiten.

Es gibt eine SO question and answers, die viele gute Lösungen hat. Aber trotzdem:

1) erste Ansatz - Entfernen Feld in save() - Methode, z. (Nicht getestet;)):

def save(self, *args, **kwargs): 
    for fname in self.readonly_fields: 
     if fname in self.cleaned_data: 
      del self.cleaned_data[fname] 
    return super(<form-name>, self).save(*args,**kwargs) 

2) zweiter Ansatz - Reset-Feldwert in saubere Methode zur anfänglichen:

def clean_<fieldname>(self): 
    return self.initial[<fieldname>] # or getattr(self.instance, <fieldname>) 

Basierend auf den zweiten Ansatz verallgemeinert ich es wie folgt aus:

from functools     import partial 

class <Form-name>(...): 

    def __init__(self, ...): 
     ... 
     super(<Form-name>, self).__init__(*args, **kwargs) 
     ... 
     for i, (fname, field) in enumerate(self.fields.iteritems()): 
      if fname in self.readonly_fields: 
       field.widget.attrs['readonly'] = "readonly" 
       field.required = False 
       # set clean method to reset value back 
       clean_method_name = "clean_%s" % fname 
       assert clean_method_name not in dir(self) 
       setattr(self, clean_method_name, partial(self._clean_for_readonly_field, fname=fname)) 


    def _clean_for_readonly_field(self, fname): 
     """ will reset value to initial - nothing will be changed 
      needs to be added dynamically - partial, see init_fields 
     """ 
     return self.initial[fname] # or getattr(self.instance, fname) 
3

Ich ging in das gleiche Problem, also habe ich ein Mixin erstellt, das für meine Anwendungsfälle zu funktionieren scheint.

class ReadOnlyFieldsMixin(object): 
    readonly_fields =() 

    def __init__(self, *args, **kwargs): 
     super(ReadOnlyFieldsMixin, self).__init__(*args, **kwargs) 
     for field in (field for name, field in self.fields.iteritems() if name in self.readonly_fields): 
      field.widget.attrs['disabled'] = 'true' 
      field.required = False 

    def clean(self): 
     cleaned_data = super(ReadOnlyFieldsMixin,self).clean() 
     for field in self.readonly_fields: 
      cleaned_data[field] = getattr(self.instance, field) 

     return cleaned_data 

Verwendung definieren nur, welche davon nur gelesen werden müssen:

class MyFormWithReadOnlyFields(ReadOnlyFieldsMixin, MyForm): 
    readonly_fields = ('field1', 'field2', 'fieldx') 
Verwandte Themen