2009-12-01 8 views
15

Mi campo de formulario se ve algo como lo siguiente:Django la creación de un campo de formulario que haya leído solamente uso de widgets

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

    class Meta: 
     model = Foo 

Consiguiendo un error como el siguiente con el código anterior: init() consiguió un argumento inesperado palabra clave 'widget'

Pensé que este es un uso legítimo de un widget de formulario?

+0

Esto cambió en Django 1.9 https://stackoverflow.com/questions/324477/in-a-django-form-how -do-i-make-a-field-readonly-or-disabled-so-that-it-can not – zudebluvstein

Respuesta

40

Debe utilizar un campo de formulario y no un campo de modelo:

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

reemplazado con

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

En caso de solucionarlo.

+1

¡Eso parece inseguro! – jpic

+0

Al punto de jpic, los usuarios pueden simplemente desactivar el indicador de solo lectura y aún enviar información. Consulte http://stackoverflow.com/a/325038/4972 para obtener una respuesta más completa. –

17

Tenga en cuenta que el atributo readonly no impide que Django procese ningún valor enviado por el cliente. Si es importante para usted que el valor no cambie, no importa cuán creativos sean sus usuarios con FireBug, debe utilizar un método más complicado, p. un ReadOnlyField/ReadOnlyWidget como demostrado en un blog entry por Alex Gaynor.

1

Como Benjamin (https://stackoverflow.com/a/2359167/565525) bien explicado, además de la representación correcta, debe procesar el campo en el backend correctamente.

Hay un SO question and answers que tiene muchas buenas soluciones. Pero de todos modos:

1) primer acercamiento - eliminación del campo en el método save(), p. (No probado;)):

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) segundo enfoque - campo de restablecimiento a valores iniciales en el método limpia:

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

Basado en segundo enfoque que generalicé así:

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

Estaba entrando en el mismo problema, así que creé un Mixin que parece funcionar para mis casos de uso.

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 

uso, simplemente definen cuáles deben ser de sólo lectura:

class MyFormWithReadOnlyFields(ReadOnlyFieldsMixin, MyForm): 
    readonly_fields = ('field1', 'field2', 'fieldx') 
Cuestiones relacionadas