How do I use a dictionary to update fields in Django models?

Question:

Suppose I have a model like this:

class Book(models.Model):
    num_pages = ...
    author = ...
    date = ...

Can I create a dictionary, and then insert or update the model using it?

d = {"num_pages":40, author:"Jack", date:"3324"}
Asked By: TIMEX

||

Answers:

Use ** for creating a new model. Loop through the dictionary and use setattr() in order to update an existing model.

From Tom Christie’s Django Rest Framework

https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/serializers.py

for attr, value in validated_data.items():
    setattr(instance, attr, value)
instance.save()

Here’s an example of create using your dictionary d:

Book.objects.create(**d)

To update an existing model, you will need to use the QuerySet filter method. Assuming you know the pk of the Book you want to update:

Book.objects.filter(pk=pk).update(**d)
Answered By: Thierry Lam

If you know you would like to create it:

Book.objects.create(**d)

Assuming you need to check for an existing instance, you can find it with get or create:

instance, created = Book.objects.get_or_create(slug=slug, defaults=d)
if not created:
    for attr, value in d.items(): 
        setattr(instance, attr, value)
    instance.save()

As mentioned in another answer, you can also use the update function on the queryset manager, but i believe that will not send any signals out (which may not matter to you if you aren’t using them). However, you probably shouldn’t use it to alter a single object:

Book.objects.filter(id=id).update()
Answered By: leech

Adding on top of other answers, here’s a bit more secure version to prevent messing up with related fields:

def is_simple_editable_field(field):
    return (
            field.editable
            and not field.primary_key
            and not isinstance(field, (ForeignObjectRel, RelatedField))
    )

def update_from_dict(instance, attrs, commit):
    allowed_field_names = {
        f.name for f in instance._meta.get_fields()
        if is_simple_editable_field(f)
    }

    for attr, val in attrs.items():
        if attr in allowed_field_names:
            setattr(instance, attr, val)

    if commit:
        instance.save()

It checks, that field you’re trying to update is editable, is not primary key and is not one of related fields.

Example usage:

book = Book.objects.first()
update_from_dict(book, {"num_pages":40, author:"Jack", date:"3324"})

The luxury DRF serializers .create and .update methods have is that there is limited and validated set of fields, which is not the case for manual update.

Answered By: Alexey Milogradov

if you have already Django object and you want to update it’s field, you may do it without filter. because you have it already, in this case, yoy may :

your_obj.__dict__.update(your_dict)
your_obj.save()
Answered By: Odiljon Djamalov

To update one record you can use very handy function:

class Book(models.Model):
    num_pages = ...
    author = ...
    date = ...

    def update(self,*args, **kwargs):
            for name,values in kwargs.items():
                try:
                    setattr(self,name,values)
                except KeyError:
                    pass
            self.save()

and then:

d = {"num_pages":40, author:"Jack", date:"3324"}
book = Book.objects.first()
book.update(**d)
Answered By: mka
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.