データベースからdjangoオブジェクトをリロードします


159

データベースからdjangoオブジェクトの状態を更新することは可能ですか?私はおおよそ次と同等の動作を意味します:

new_self = self.__class__.objects.get(pk=self.pk)
for each field of the record:
    setattr(self, field, getattr(new_self, field))

更新:トラッカーで再オープン/不変の戦争が見つかりました:http ://code.djangoproject.com/ticket/901 。それでも、メンテナがこれを好まない理由がわかりません。


通常のSQLコンテキストでは、これは意味がありません。データベースオブジェクトは、トランザクションが終了してを実行した後でのみ変更できますcommmit。それが完了したら、次のSQLトランザクションがコミットするのを待つ必要があります。なぜそれをするのですか?次の取引をどのくらい待ちますか?
S.Lott、

これは不要な関数のようです。データベースからオブジェクトを再検索することはすでに可能です。
Stephan

私もこれを希望しますが、ここでは
eruciform

2
Djangoモデルオブジェクトはプロキシであるため、適切ではありません。同じテーブル行を2つのオブジェクトに取得する場合-x1 = X.objects.get(id = 1); x2 = X.objects.get(id = 1)、等しいとテストされますが、それらは異なるオブジェクトであり、状態は共有されません。両方を個別に変更して保存することができます。最後に保存されたものがデータベースの行の状態を決定します。したがって、単純な割り当て-x1 = X.objects.get(id = 1)でリロードするのが正しいです。reloadメソッドを使用すると、多くの人がx1.f = 'new value';と誤って推測することになります。(x1.f == x2.f)はTrueです。
ポールウィップ2014

回答:


258

Django 1.8以降、更新オブジェクトが組み込まれています。ドキュメントへのリンク

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

@ fcracker79ええ、それは1.8でのみ実装されました。Djangoの以前のバージョンでは、他の答えの1つを使用するのが最善です。
Tim Fletcher

1
ドキュメントで言及されている「すべての非遅延フィールドが更新されました」が何を意味するのかわからないのですか?
Yunti 2015年

1
@Yunti フィールドを延期するか、フィールドのサブセットのみを明示的に要求すると、結果のオブジェクトは部分的にのみ入力されます。refresh_from_dbそのようなすでに入力されたフィールドのみを更新します。
301_Moved_Permanently

ドキュメントで詳細を見つけることができませんでしたDoesNotExistが、を呼び出すときに基礎となるオブジェクトが削除された場合は、例外を適切にスローしますrefresh_from_db。ご参考までに。
Tim Tisdall、

28

次のようにして、データベースからオブジェクトリロードするのは比較的簡単です。

x = X.objects.get(id=x.id)

19
はい、しかし...その後、このオブジェクトへのすべての参照を更新する必要があります。あまり便利ではなく、エラーが発生しやすい。
grep

2
Celeryがdjangoの外のdbでオブジェクトを更新したときにこれが必要であることがわかりました。djangoは、変更されたことがわからなかったため、オブジェクトのキャッシュを保持しているようです。
Bob Spryn

3
django.db.models.loadingからimport get_model; instance = get_model(instance).objects.get(pk = instance.pk)
Erik

1
@grepは、このユースケースのテストの作成に2時間かかっただけです。1:モデルを初期化します。2:フォームを介してモデルを更新します。3:新しい値が更新されていることをテストします。
vlad-ardelean 2014年

3
私はrefresh_from_dbこれらすべての問題を解決すると思います。
Flimm 2017年

16

@grepのコメントを参照して、それを行うことはできないはずです:

# Put this on your base model (or monkey patch it onto django's Model if that's your thing)
def reload(self):
    new_self = self.__class__.objects.get(pk=self.pk)
    # You may want to clear out the old dict first or perform a selective merge
    self.__dict__.update(new_self.__dict__)

# Use it like this
bar.foo = foo
assert bar.foo.pk is None
foo.save()
foo.reload()
assert bar.foo is foo and bar.foo.pk is not None

解決策をありがとう。SOのみが複数の投票を許可した場合!
user590028 2016年

11
Djangoはrefresh_from_dbメソッドを提供します。
Flimm 2017年

9

@Flimmが指摘したように、これは本当に素晴らしいソリューションです。

foo.refresh_from_db()

これにより、データベースからオブジェクトにすべてのデータが再ロードされます。

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