2009-10-16 33 views
43

Me pregunto, ¿cuál es una forma estándar de actualizar múltiples campos de una instancia de un modelo en django? ... Si tengo un modelo con algunos campos,¿Cómo actualizar múltiples campos de una instancia de modelo django?

Class foomodel(models.Model): 
    field1 = models.CharField(max_length=10) 
    field2 = models.CharField(max_length=10) 
    field3 = models.CharField(max_length=10) 
    ... 

... y yo instanciarlo con un campo dado, y luego en una etapa distinta quiero proveer el resto de los campos, ¿cómo hacer eso solo pasando un diccionario o parametros de valor clave? ¿Posible?

En otras palabras, supongamos que tengo un diccionario con algunos datos que tienen todo lo que quiero escribir en una instancia de ese modelo. La instancia del modelo se ha instanciado en un paso separado y digamos que aún no se ha conservado. Puedo decir foo_instance.field1 = my_data_dict['field1'] para cada campo, pero algo me dice que debería haber una forma de invocar un método en la instancia del modelo donde paso todos los pares de valor de campo a la vez y los actualiza. Algo así como foo_instance.update(my_data_dict). No veo ningún método integrado como este, ¿me lo estoy perdiendo o cómo se hace de manera eficiente?

Tengo la sensación de que esta es una pregunta obvia de RTM, pero no la he visto en los documentos.

Respuesta

93

Es tentador meterse con __dict__, pero que no se aplicará a los atributos heredados de una clase padre.

Usted puede iterar sobre el dict para asignar al objeto:

for (key, value) in my_data_dict.items(): 
    setattr(obj, key, value) 

O puede modificar directamente desde un conjunto de consultas (asegurándose de que su consulta establece sólo devuelve el objeto que le interesa):

FooModel.objects.filter(whatever="anything").update(**my_data_dict) 
+0

¿funciona esto con los campos m2m? –

24

Usted podría intentar esto:

obj.__dict__.update(my_data_dict) 
+6

Esto no se aplicará a los atributos heredados. –

+1

¿Cuáles son las implicaciones del hecho de que no se aplicará a los atributos heredados? –

+0

Además, está tratando de actualizar una ForeignKey, usando __dict__, los nombres de valores relacionados son 'field_name_id' not' field_name', debe tener cuidado con eso. – levi

3

Parece una cosa tan natural que querrías hacer pero, como tú, tampoco la he encontrado en los documentos. Los documentos dicen que debe sub-clase save() en el modelo. Y eso es lo que hago.

def save(self, **kwargs): 
    mfields = iter(self._meta.fields) 
    mods = [(f.attname, kwargs[f.attname]) for f in mfields if f.attname in kwargs] 
    for fname, fval in mods: setattr(self, fname, fval) 
    super(MyModel, self).save() 
+1

Pensando en hacer un decorador para modelos que agrega un nuevo método "dict_save" (así que 2 métodos de guardado para el modelo - normal y dict) con el cuerpo sobre la próxima vez que lo necesite. Busqué el código que solía hacer esto y es el mismo excepto que lo estaba haciendo fuera de guardar.Tenía un método update_model_obj_from_dict (model_object, update_dict) con prácticamente el mismo cuerpo que el anterior y esperaba que elegiría cuándo llamar a save() después. Me gusta tener la opción. así que tal vez un método en el modelo llamado "set_from_dict" con todo lo anterior excepto la última línea y simplemente usar guardar más tarde. – Purrell

2

me sale el nombre de la clave primaria, lo utilizan para filtrar con Queryset.filter() y la actualización con Queryset.update().

fooinstance = ...  
# Find primary key and make a dict for filter 
pk_name foomodel._meta.pk.name 
filtr = {pk_name: getattr(fooinstance, pk_name)} 
# Create a dict attribute to update 
updat = {'name': 'foo', 'lastname': 'bar'} 
# Apply 
foomodel.objects.filter(**filtr).update(**updat) 

Esto me permite actualizar una instancia cualquiera que sea la clave principal.

1

Actualización mediante update()

Discussion.objects.filter(slug=d.slug) 
    .update(title=form_data['title'], 
      category=get_object_or_404(Category, pk=form_data['category']), 
      description=form_data['description'], closed=True) 
+0

Bienvenido a SO. Cuando publique respuestas, incluya una explicación de su código y recuerde formatear el texto. – Tony

Cuestiones relacionadas