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

55,169

Solution 1

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)

Solution 2

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

Solution 3

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

Solution 4

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

Solution 5

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)
Share:
55,169

Related videos on Youtube

TIMEX
Author by

TIMEX

Updated on August 21, 2021

Comments

  • TIMEX
    TIMEX over 2 years

    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"}
    
  • TIMEX
    TIMEX about 13 years
    Huh? Can you give an example? So, I would have to write a custom function that loops through the dictionary?
  • user1066101
    user1066101 about 13 years
    @TIMEX: Please read. docs.python.org/reference/expressions.html#calls is very clear on how this works.
  • Thierry Lam
    Thierry Lam over 10 years
    I think update only works on a QuerySet not on a single object.
  • Jorge Leitao
    Jorge Leitao about 10 years
    Doesn't your create code leads to 2 database hits? One for creating, the other for .save()?
  • leech
    leech about 10 years
    Yes, but not to save. If it has been created, there will be one to lookup the Book (SELECT), then another to update it (an UPDATE not INSERT statement will be generated). If the book doesn't exist, there is one to look it up (SELECT) and create it (INSERT).
  • redacted
    redacted over 7 years
    Could you explain why using ** for updating might not be a good idea?
  • CrowbarKZ
    CrowbarKZ over 7 years
    @Pocin using queryset.update(**fields) is a good idea according to django docs. Quote: "If you’re just updating a record and don’t need to do anything with the model object, the most efficient approach is to call update(), rather than loading the model object into memory."
  • Wtower
    Wtower about 7 years
    Be careful: update() does not respect signals. See the answer by @leech below.
  • Wtower
    Wtower about 7 years
    that will not send any signals out: cannot stress this out enough.
  • Bryant James
    Bryant James almost 7 years
    Good answer, the call is very explicit. Not a fan of filter(...).update(...) since bungling the filter can lead to mass overwrites.
  • MikeyE
    MikeyE almost 4 years
    I agree with Bryant Jackson. And also it seems a bit easier to understand the code when operating on a single instance.
  • joshlsullivan
    joshlsullivan over 3 years
    This is brilliant.
  • Scott
    Scott over 3 years
    Please add a ".": your_obj.__dict__.update(your_dict)
  • radtek
    radtek about 3 years
    Hmm too bad update and update_or_create don't take using parameter, only save() does.
  • Gokberk Yar
    Gokberk Yar almost 3 years
    TLDR : Won't work for object fields. Details: If your fields are not basic types like str, int ie an object like Entry. It won't work.