web-dev-qa-db-ja.com

Django model custom save()メソッドでは、新しいオブジェクトをどのように識別する必要がありますか?

新しいレコードを保存するときに(既存のレコードを更新しないで)Django=モデルオブジェクトのsave()メソッドで特別なアクションをトリガーします。)

(self.id!= None)のチェックは、自己レコードが新規で更新されていないことを保証するために必要かつ十分ですか?これが見落とす可能性のある特別なケースはありますか?

146
MikeN
self.pk is None:

オブジェクトがprimary_keyとしてUUIDFieldを持たない限り、新しいModelオブジェクト内でTrueを返します。

心配しなければならない可能性のあるケースは、id以外のフィールドに一意性の制約があるかどうかです(たとえば、他のフィールドのセカンダリ一意インデックス)。その場合、新しいレコードを手に入れることはできますが、保存することはできません。

183
Dave W. Smith

self.pkをチェックする別の方法モデルのself._stateをチェックできます

self._state.adding is True作成

self._state.adding is False更新

これから得た ページ

139
SaintTail

self.idは、idがモデルの主キーであると想定しています。より一般的な方法は、 pkショートカット を使用することです。

is_new = self.pk is None

42
Gerry

self.pk == Noneのチェックはnotで、オブジェクトがデータベースに挿入または更新されるかどうかを判断するのに十分です。

Django O/RMは、PK位置に何かがあるかどうかを確認し、そうであればUPDATEを行い、そうでない場合はINSERTを実行する(これはINSERTに対して最適化されます) PKがNoneの場合)。

これを行う必要があるのは、オブジェクトの作成時にPKを設定できるためです。主キーのシーケンス列がある場合は一般的ではありませんが、これは他のタイプの主キーフィールドには当てはまりません。

本当に知りたい場合は、O/RMが行うことを実行し、データベースを調べる必要があります。

もちろん、コードに特定のケースがあり、そのためにself.pk == Noneがあなたが知る必要があるすべてをあなたに伝える可能性が高いですが、それはnot一般的なソリューション。

38
KayEss

「作成済み」のkwargsを送信するpost_save信号に接続するだけで済みます。trueの場合、オブジェクトが挿入されています。

http://docs.djangoproject.com/en/stable/ref/signals/#post-save

9
JF Simon

self.id そしてその force_insert 国旗。

if not self.pk or kwargs.get('force_insert', False):
    self.created = True

# call save method.
super(self.__class__, self).save(*args, **kwargs)

#Do all your post save actions in the if block.
if getattr(self, 'created', False):
    # So something
    # Do something else

これは、新しく作成されたオブジェクト(self)にpk値があるため便利です。

7
Kwaw Annor

私はこの会話に非常に遅れていますが、デフォルト値が関連付けられているときにself.pkが読み込まれるという問題に遭遇しました。

これを回避する方法は、モデルにdate_createdフィールドを追加することです

date_created = models.DateTimeField(auto_now_add=True)

ここから行くことができます

created = self.date_created is None

5
Jordan

むしろidの代わりにpkを使用してください:

if not self.pk:
  do_something()
4
yedpodtrzitko

UUIDFieldを主キーとしても機能するソリューションの場合(他の人が指摘しているように、Noneをオーバーライドするだけではsaveではありません)、 Djangoの post_save シグナルに接続します。これをmodels.pyに追加します:

from Django.db.models.signals import post_save
from Django.dispatch import receiver

@receiver(post_save, sender=MyModel)
def mymodel_saved(sender, instance, created, **kwargs):
    if created:
        # do extra work on your instance, e.g.
        # instance.generate_avatar()
        # instance.send_email_notification()
        pass

このコールバックはsaveメソッドをブロックするため、フォームを使用している場合でもDjango REST AJAX呼び出しのフレームワーク。もちろん、責任を持って使用し、ユーザーを待たせずに重いタスクをジョブキューにオフロードします:)

4
metakermit

これが一般的な方法です。

iDは、dbに最初に保存されている間に与えられます

1
vikingosegundo

これは上記のすべてのシナリオで機能しますか?

if self.pk is not None and <ModelName>.objects.filter(pk=self.pk).exists():
...
0
Sachin