2010-06-07 35 views
20

en mi proyecto Django (1.2), quiero completar previamente un campo en un modelo, pero mi nuevo valor es ignorado. Este es el fragmento:Reemplazando el valor inicial en ModelForm

class ArtefactForm(ModelForm): 
    material = CharField(widget=AutoCompleteWidget('material', force_selection=False)) 

    def __init__(self, *args, **kwargs): 
     super(ArtefactForm, self).__init__(*args, **kwargs) 
     self.fields['material'].initial = 'Test' 

También probé con self.base_fields, pero ningún efecto: siempre existe la base de datos de valor se presentan en forma. ¿Algunas ideas?

Respuesta

39

Prueba esto:

def __init__(self, *args, **kwargs): 
    initial = kwargs.get('initial', {}) 
    initial['material'] = 'Test' 
    kwargs['initial'] = initial 
    super(ArtefactForm, self).__init__(*args, **kwargs) 
+0

perfecto, gracias. – schneck

10

vieja pregunta, pero añadiendo una respuesta descriptiva, ya que creo que sería útil para un nuevo desarrollador.

También probé con self. base_fields, pero no tiene efecto: siempre se visualiza el valor de la base de datos en el formulario. ¿Algunas ideas?

Si un formulario se "inicializa" forma, ya sea: -

  1. usando initial argumento (. Ej YourModelFrom(initial={'filed1': variable}) — generalmente el caso, cuando se quiere pasar valores iniciales calculados dinámicamente para algunos campos) . Referencia Setting Initial Values

    o

  2. usando instance argumento (por ejemplo. YourModelFrom(instance=model_object) — suele ser el caso, cuando se quiere actualizar un objeto instancia de modelo existente). Referencias más de ModelFrom save() method

    Nota:
    clase hereda `BaseModelFrom` clase. La clase `BaseModelFrom` hereda la clase `BaseForm`.
    2 El argumento instance se añade en `BaseModelFrom` constructor de la clase, cuando asignamos un objeto de modelo de instancia de clase a instance argumento (de ahí instance is not None) entonces `BaseModelFrom` constructor llama model_to_dict() y actualizaciones initial argumento antes de llamar a super constructor de clase. Compruebe def __init__ en clase BaseModelFrom

A continuación, asignar un valor inicial a un campo de forma explícita (como se muestra en el código de OP en cuestión) no efecto, esto es debido a la forma _clean_fields método está escrito en BaseFrom clase.

Código Snip:

def _clean_fields(self): 
    for name, field in self.fields.items(): 
     value = field.widget.value_from_datadict(
       self.data, self.files, self.add_prefix(name)) 
     try: 
      if isinstance(field, FileField): 
       initial = self.initial.get(name, field.initial) # <- Check 
       value = field.clean(value, initial) 
      else: 

De acuerdo con la línea de código initial = self.initial.get(name, field.initial), si el valor inicial para el campo se da en initial dict entonces el valor asignado a field.initial es no utilizado.

[RESPUESTA]:

Aunque, @ Daniel respuesta es perfectamente correcto, pero uno puede también como otra manera de lograr mismo efecto es el uso de self.initial:

def __init__(self, *args, **kwargs): 
    super(ArtefactForm, self).__init__(*args, **kwargs) 
    self.initial['material'] = 'Test' 

darle una oportunidad !!

self.initial no es más que el dict que pasamos en discusión. Verificar código __init__ en BaseForm:

class BaseForm(object): 
    def __init__(........ 
       ........): 
     : 
     self.prefix = prefix 
     self.initial = initial or {} # <-- Notice 
     self.error_class = error_class 
     : 

Nota: No he encontrado ninguna documentación relacionada con el uso del atributo inicial, sólo exploró el código base y la utilicé.

Editar: el comportamiento reportado en cuestión también se documenta en Django Modelo

Dynamic initial values

Form.initial

Tenga en cuenta que si un Field define initial y que incluyen initial cuando instancia el formulario, entonces el último initial tendrá prioridad. En este ejemplo, initial se proporciona tanto a nivel de terreno y en el nivel de instancia de formulario, y este último obtiene precedencia:

>>> from django import forms 
>>> class CommentForm(forms.Form): 
...  name = forms.CharField(initial='class') 
...  url = forms.URLField() 
...  comment = forms.CharField() 
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False) 
>>> print(f) 
<tr><th>Name:</th><td><input type="text" name="name" value="instance" /> 
<tr><th>Url:</th><td><input type="url" name="url" /></td></tr> 
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> 

PD: Por cierto, el punto 2, en mis respuestas diga diferencia entre initial y instance argumento. Su es un argumento de valor-clave más data - los valores en eso activan las validaciones de formulario. lea esto Difference between Django Form 'initial' and 'bound data'?.

+0

** Nota: ** En forma enlazada, 'data' (el dict de consulta) tendrá precedencia sobre el valor del campo inicializado. Código de verificación: ['def value (self)'] (https://github.com/django/django/blob/master/django/forms/forms.py#L610) y el método ['def bound_data (self, data, initial) '] (https://github.com/django/django/blob/master/django/forms/fields.py#L165) - esto le ayudará si tiene un valor para un campo os dinámicamente calculado y el archivado es ['disabled'] (http://stackoverflow.com/a/1424453/1673391). ¡Avíseme si alguien necesita ayuda con esto, actualizaré esta respuesta! –

+0

¡Gran respuesta, gracias! Con respecto a la configuración del valor inicial, me gustaría agregar una solución [Encontré] (https://stackoverflow.com/a/22390638/2996101): 'self.fields [field_name] .initial = field_value' – raratiru

Cuestiones relacionadas