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

前端 未结 5 1770
盖世英雄少女心
盖世英雄少女心 2020-12-23 02:21

Suppose I have a model like this:

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

Can I create a dictionary,

相关标签:
5条回答
  • 2020-12-23 02:38

    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()
    
    0 讨论(0)
  • 2020-12-23 02:49

    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)
    
    0 讨论(0)
  • 2020-12-23 02:51

    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()
    
    0 讨论(0)
  • 2020-12-23 02:51

    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()
    
    0 讨论(0)
  • 2020-12-23 02:52

    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.

    0 讨论(0)
提交回复
热议问题