web-dev-qa-db-ja.com

Django:.get()によって取得された単一のモデルインスタンスで.update()を呼び出しますか?

現在Models.object.get()を呼び出す関数があり、0または1つのモデルオブジェクトを返します。 0が返される場合、関数の_except DoesNotExist_句に新しいモデルインスタンスを作成します。そうでない場合は、新しいインスタンスを作成せずに、既存のインスタンスのフィールドを更新したいと思います。私はもともと、見つかったインスタンスで.update()を呼び出そうとしましたが、.update()はQuerySetsでのみ呼び出し可能と思われます。 .filter()を呼び出して、既存のインスタンスを作成または更新する必要があるかどうかを知るために長さを比較せずに、1ダースのフィールドを変更するにはどうすればよいですか?

47
zhuyxn

Django 1.7の出現により、新しい _update_or_create_ QuerySetメソッドが追加されました。データベースレベルで一意性が強制されない場合の条件。

ドキュメントの例:

_obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)
_

_update_or_create_メソッドは、指定されたkwargsに基づいてデータベースからオブジェクトをフェッチしようとします。一致が見つかった場合、defaults辞書で渡されたフィールドを更新します。


Django 1.7より前:

必要に応じてモデルフィールドの値を変更し、.save()を呼び出して変更を永続化します。

_try:
    obj = Model.objects.get(field=value)
    obj.field = new_value
    obj.save()
except Model.DoesNotExist:
    obj = Model.objects.create(field=new_value)
# do something else with obj if need be
_
56
Platinum Azure

Django 1.5の時点で、モデルの保存にはupdate_fieldsプロパティがあります。例:

obj.save(update_fields=['field1', 'field2', ...])

https://docs.djangoproject.com/en/dev/ref/models/instances/

モデルインスタンスのさまざまな部分を変更する複数のWebアプリインスタンスがある場合、原子性の問題が発生しないため、このアプローチを好みます。

35
Nils

存在する場合にのみモデルを更新する場合(作成せずに):

Model.objects.filter(id = 223).update(field1 = 2)

mysqlクエリ:

UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223
24
Eyal Ch

これがどれだけ良いか悪いかはわかりませんが、次のようなものを試すことができます。

try:
    obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
    obj = Model.objects.create()
obj.__dict__.update(your_fields_dict) 
obj.save()
20
Rohan

以下に、各インスタンスにupdateメソッドを与える任意のモデルクラスにミックスできるミックスインを示します。

class UpdateMixin(object):
    def update(self, **kwargs):
        if self._state.adding:
            raise self.DoesNotExist
        for field, value in kwargs.items():
            setattr(self, field, value)
        self.save(update_fields=kwargs.keys())

self._state.adding checkは、モデルがデータベースに保存されているかどうかを確認し、保存されていない場合はエラーを発生させます。

(注:このupdateメソッドは、モデルを更新し、インスタンスが既にデータベースに保存されていることがわかっている場合に使用します。元の質問に直接答えます。組み込みのupdate_or_create Platinum Azureの回答で紹介されているメソッドは、すでに他のユースケースをカバーしています。)

次のように使用します(これをユーザーモデルに混合した後):

user = request.user
user.update(favorite_food="ramen")

より良いAPIを持つことに加えて、このアプローチのもう1つの利点は、pre_saveおよびpost_saveフック。別のプロセスが同じモデルを更新している場合でも、原子性の問題を回避します。

7
Julien

@Nilsが言及したように、save()メソッドのupdate_fieldsキーワード引数を使用して、更新するフィールドを手動で指定できます。

obj_instance = Model.objects.get(field=value)
obj_instance.field = new_value
obj_instance.field2 = new_value2

obj_instance.save(update_fields=['field', 'field2'])

update_fields値は、文字列として更新するフィールドのリストである必要があります。

https://docs.djangoproject.com/en/2.1/ref/models/instances/#specifying-which-fields-to-save を参照してください

0
Rémi Héneault

私はそのような場合に次のコードを使用しています:

obj, created = Model.objects.get_or_create(id=some_id)

if not created:
   resp= "It was created"
else:
   resp= "OK"
   obj.save()
0
Aragon