現在Models.object.get()
を呼び出す関数があり、0または1つのモデルオブジェクトを返します。 0が返される場合、関数の_except DoesNotExist
_句に新しいモデルインスタンスを作成します。そうでない場合は、新しいインスタンスを作成せずに、既存のインスタンスのフィールドを更新したいと思います。私はもともと、見つかったインスタンスで.update()
を呼び出そうとしましたが、.update()
はQuerySetsでのみ呼び出し可能と思われます。 .filter()
を呼び出して、既存のインスタンスを作成または更新する必要があるかどうかを知るために長さを比較せずに、1ダースのフィールドを変更するにはどうすればよいですか?
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
_
Django 1.5の時点で、モデルの保存にはupdate_fieldsプロパティがあります。例:
obj.save(update_fields=['field1', 'field2', ...])
https://docs.djangoproject.com/en/dev/ref/models/instances/
モデルインスタンスのさまざまな部分を変更する複数のWebアプリインスタンスがある場合、原子性の問題が発生しないため、このアプローチを好みます。
存在する場合にのみモデルを更新する場合(作成せずに):
Model.objects.filter(id = 223).update(field1 = 2)
mysqlクエリ:
UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223
これがどれだけ良いか悪いかはわかりませんが、次のようなものを試すことができます。
try:
obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
obj = Model.objects.create()
obj.__dict__.update(your_fields_dict)
obj.save()
以下に、各インスタンスに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
フック。別のプロセスが同じモデルを更新している場合でも、原子性の問題を回避します。
@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 を参照してください
私はそのような場合に次のコードを使用しています:
obj, created = Model.objects.get_or_create(id=some_id)
if not created:
resp= "It was created"
else:
resp= "OK"
obj.save()