Suppose I have a model like this:
class Book(models.Model):
num_pages = ...
author = ...
date = ...
Can I create a dictionary,
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)
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()
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()
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.