How to update multiple fields of a django model instance?

I'm wondering, what is a standard way of updating multiple fields of an instance of a model in django? ... If I have a model with some fields,

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

... and I instantiate it with one field given, and then in a separate step I want to provide the rest of the fields, how do I do that by just passing a dictionary or key value params? Possible?

In other words, say I have a dictionary with some data in it that has everything I want to write into an instance of that model. The model instance has been instantiated in a separate step and let's say it hasn't been persisted yet. I can say foo_instance.field1 = my_data_dict['field1'] for each field, but something tells me there should be a way of calling a method on the model instance where I just pass all of the field-value pairs at once and it updates them. Something like foo_instance.update(my_data_dict). I don't see any built-in methods like this, am I missing it or how is this efficiently done?

I have a feeling this is an obvious, RTM kind of question but I just haven't seen it in the docs.


It's tempting to mess with __dict__, but that won't apply to attributes inherited from a parent class.

You can either iterate over the dict to assign to the object:

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

Or you can directly modify it from a queryset (making sure your query set only returns the object you're interested in):

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

You could try this:

obj.__dict__.update(my_data_dict)

It seems like such a natural thing you'd want to do but like you I've not found it in the docs either. The docs do say you should sub-class save() on the model. And that's what I do.

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()

I get primary key's name, use it to filter with Queryset.filter() and update with 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)

This allows me to update an instance whatever the primary key.