web-dev-qa-db-ja.com

辞書を使用してDjangoモデルのフィールドを更新するにはどうすればよいですか?

次のようなモデルがあるとします:

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

辞書を作成し、それを使用してモデルを挿入または更新できますか?

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

辞書dを使用して作成する例を次に示します。

Book.objects.create(**d)

既存のモデルを更新するには、QuerySet filterメソッドを使用する必要があります。更新する本のpkを知っていると仮定します:

Book.objects.filter(pk=pk).update(**d)
86
Thierry Lam

作成することがわかっている場合:

Book.objects.create(**d)

既存のインスタンスを確認する必要がある場合、getまたはcreateで検索できます。

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

別の回答で述べたように、クエリセットマネージャーでupdate関数を使用することもできますが、信号を送信しません(それらを使用していない場合は問題になりません)。ただし、単一のオブジェクトを変更するために使用しないでください。

Book.objects.filter(id=id).update()
49
leech

_**_を使用して、新しいモデルを作成します。辞書をループして、setattr()を使用して既存のモデルを更新します。

Tom Christieの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()
_

他の回答に加えて、関連フィールドとの干渉を防ぐためのもう少し安全なバージョンがあります。

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

更新しようとしているフィールドが編集可能であり、主キーではなく、関連するフィールドでもないことを確認します。

使用例:

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

高級DRFシリアライザー.createおよび.updateメソッドには、限られた検証済みのフィールドセットがありますが、手動更新の場合はそうではありません。

0