Djangoモデルを作成するか、存在する場合は更新します


114

PersonのIDが存在しない場合、Personなどのモデルオブジェクトを作成するか、そのPersonオブジェクトを取得します。

次のように新しい人を作成するコード:

class Person(models.Model):
    identifier = models.CharField(max_length = 10)
    name = models.CharField(max_length = 20)
    objects = PersonManager()

class PersonManager(models.Manager):
    def create_person(self, identifier):
        person = self.create(identifier = identifier)
        return person

しかし、既存の人物オブジェクトをどこで確認して取得するのかわかりません。

回答:


169

「存在する場合は更新、その他の場合は作成」のユースケースを探している場合は、@ Zagsの優れた回答を参照してください


Djangoにはすでにget_or_create https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

あなたにとっては:

id = 'some identifier'
person, created = Person.objects.get_or_create(identifier=id)

if created:
   # means you have created a new person
else:
   # person just refers to the existing one

私はdjango 1.9を使用していますが、それにより次の結果が得られます:AttributeError: 'QuerySet' object has no attribute 'update_or_create'
Ofek Gila

1
@OfekGila奇妙なことですが、ソースコードドキュメントの両方で確認されQuerySetていますupdate_or_create
bakkal

2
私の場合、識別子の代わりに、unique_togetherを形成するフィールドのグループがあります。この場合の使用法はどうですか?
Rakmo 2018年

191

あなたの質問がget_or_createメソッド(少なくともDjango 1.3から利用可能)を要求しているか、update_or_createメソッド(Django 1.7の新機能)を要求しているかは不明です。ユーザーオブジェクトの更新方法によって異なります。

使用例は次のとおりです。

# In both cases, the call will get a person object with matching
# identifier or create one if none exists; if a person is created,
# it will be created with name equal to the value in `name`.

# In this case, if the Person already exists, its existing name is preserved
person, created = Person.objects.get_or_create(
        identifier=identifier, defaults={"name": name}
)

# In this case, if the Person already exists, its name is updated
person, created = Person.objects.update_or_create(
        identifier=identifier, defaults={"name": name}
)

12
+1はupdate_or_create、そのユースケースでは、オブジェクトを再度get_or_create呼び出すよりも優れているためですsave()
bakkal

私の場合、識別子の代わりに、unique_togetherを形成するフィールドのグループがあります。この場合の使用法はどうですか?
Rakmo 2018年

1
@OmkarDeshpande識別子は単なる例です。次のような有効なdjangoクエリを渡すことができますPerson.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
Zags

作成した個人にデフォルトのフィールドよりも多くのフィールドを追加したい場合はどうなりますか?
ローベリン

@LoBellin defaultsこれらの関数の引数は、モデルに追加するフィールドを指定する場所です。モデルのフィールドに指定されたデフォルトとは関係ありません
Zags


4

少量のオブジェクトの場合、update_or_create適切に機能しますが、大きなコレクションを処理している場合、適切にスケーリングされません。update_or_createは常に最初にSELECTを実行し、その後にUPDATEを実行します。

for the_bar in bars:
    updated_rows = SomeModel.objects.filter(bar=the_bar).update(foo=100)
        if not updated_rows:
            # if not exists, create new
            SomeModel.objects.create(bar=the_bar, foo=100)

これは、せいぜい最初の更新クエリのみを実行し、一致する行がゼロの場合にのみ、別のINSERTクエリを実行します。ほとんどの行が実際に存在すると予想される場合、これによりパフォーマンスが大幅に向上します。

しかし、それはすべてあなたのユースケースに帰着します。ほとんど挿入が必要な場合は、おそらくbulk_create()コマンドがオプションになる可能性があります。


3

質問のタイトルは、質問の本文で説明されているように取得または作成するのではなく、作成または更新する方法を尋ねているように見えるため、回答を追加すると思います。

オブジェクトを作成または更新したい場合、.save()メソッドはデフォルトで既にこの動作をしており、docsから:

DjangoはINSERTまたはUPDATE SQLステートメントを使用する必要性を抽象化します。特に、save()を呼び出すと、Djangoは次のアルゴリズムに従います。

オブジェクトの主キー属性がTrueと評価される値(つまり、Noneまたは空の文字列以外の値)に設定されている場合、DjangoはUPDATEを実行します。オブジェクトの主キー属性が設定されていない場合、またはUPDATEが何も更新しなかった場合、DjangoはINSERTを実行します。

彼らが「UPDATEが何も更新しなかった場合」と言うとき、それらは本質的に、オブジェクトに与えたIDがデータベースにまだ存在していない場合を指していることに注意する価値があります。


1

作成時の入力の1つが主キーの場合、これで十分です。

Person.objects.get_or_create(id=1)

同じ主キーを持つ2つのデータは許可されないため、存在する場合は自動的に更新されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.