Django-Model.create()メソッドをオーバーライドしますか?


89

Djangoのドキュメントはのみ上書きする例リストsave()とをdelete()。ただし、モデルが作成されたときにのみ、モデルに追加の処理を定義したいと思います。Railsに精通している人にとっては、:before_createフィルターを作成するのと同じです。これは可能ですか?

回答:


164

オーバーライド__init__()すると、オブジェクトのPython表現がインスタンス化されるたびにコードが実行されます。レールはわかりませんが:before_created、データベースにオブジェクトが作成されたときに実行されるコードのように聞こえます。データベースに新しいオブジェクトが作成されたときにコードを実行save()する場合は、オブジェクトにpk属性があるかどうかを確認して、オーバーライドする必要があります。コードは次のようになります。

def save(self, *args, **kwargs):
    if not self.pk:
        # This code only happens if the objects is
        # not in the database yet. Otherwise it would
        # have pk
    super(MyModel, self).save(*args, **kwargs)

7
私は実際にシグナルを使用した解決策を見つけました:docs.djangoproject.com/en/dev/topics/signals(具体的にはpre_saveシグナル)。ただし、これははるかに実用的な解決策のようです。本当にありがとう。
Ground5hark 2010

4
私はあなたがマネージャーメソッドをオーバーライドすることを意味すると思いますcreateか?これは興味深い解決策ですが、オブジェクトがObject(**kwargs).save()それを使用して、またはその他のバリエーションを使用して作成されている場合は機能しません。
ザック

4
私はそれがハックだとは思わない。これは公式の解決策の1つです。
les

6
そうではないsuper(MyModel, self).save(*args, **kwargs)ですか?
Mark Chackerian 2017年

1
self.pkオブジェクトが新しく作成されているのか、単に更新されているのかを確認するのに最適なオプションではないかもしれません。作成時にオブジェクトID(のようなカスタマイズされた非データベース生成値KSUID)を指定すると、この句が実行さself._state.addingれない場合があります...初めて保存するのか、単に更新するだけなのかを確認する値があります。そのような場合に役立ちます。
シャヒニズム

22

これは古く、受け入れられた答えが機能し(Zachのもの)、より慣用的なもの(Michael Bylstraのもの)もありますが、それでもほとんどの人が見るGoogleでの最初の結果であるため、よりベストプラクティスのモダンなdjangoが必要だと思いますここでスタイルの答え

from django.db.models.signals import post_save

class MyModel(models.Model):
    # ...
    @classmethod
    def post_create(cls, sender, instance, created, *args, **kwargs):
        if not created:
            return
        # ...what needs to happen on create

post_save.connect(MyModel.post_create, sender=MyModel)

ポイントはこれです:

  1. シグナルを使用する(続きを読む 公式ドキュメントでください)
  2. 素敵な名前空間の方法を使用してください(それが理にかなっている場合)...そして私はそれを次のようにマークしました @classmethod@staticmethod、コードで静的クラスメンバーを参照する必要がある可能性が高いため代わりました

コアDjangoに実際のpost_create信号があれば、さらにクリーンになります。(メソッドの動作を変更するためにブール引数を渡す必要がある場合は、2つのメソッドである必要があります。)


22

post_saveシグナルを作成する方法の例(http://djangosnippets.org/snippets/500/から)

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

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    """Create a matching profile whenever a user object is created."""
    if created: 
        profile, new = UserProfile.objects.get_or_create(user=instance)

シグナルを使用するのが最善か、カスタム保存方法を使用するのが最善かについての思慮深い議論がここにありますhttps://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/29/ django-signals-vs-custom-save-method /

私の意見では、このタスクにシグナルを使用すると、より堅牢で読みやすくなりますが、時間がかかります。


これは、オブジェクトの内部をいじる代わりに推奨される方法ですが、上記の例でモデルを作成するだけでなく、問題のモデルに変更を加える場合は、を呼び出すことを忘れないでくださいinstance.save()。したがって、この場合、データベースへのINSERTクエリとUPDATEクエリが1つずつあるため、パフォーマンスが低下します。
マイクシュルツ2015

シグナルとカスタム保存メソッドへのリンクが壊れています。
Sander Vanden Hautte 2018

18

文字通り質問に答えるためcreateに、モデルのマネージャーのメソッドは、Djangoで新しいオブジェクトを作成するための標準的な方法です。オーバーライドするには、次のような操作を行います

from django.db import models

class MyModelManager(models.Manager):
    def create(self, **obj_data):
        # Do some extra stuff here on the submitted data before saving...
        # For example...
        obj_data['my_field'] = my_computed_value(obj_data['my_other_field'])

        # Now call the super method which does the actual creation
        return super().create(**obj_data) # Python 3 syntax!!

class MyModel(models.model):
    # An example model
    my_field = models.CharField(max_length=250)
    my_other_field = models.CharField(max_length=250)

    objects = MyModelManager()

この例では、Managerのメソッドをオーバーライドしています createは、インスタンスが実際に作成される前に、メソッドをして追加の処理を実行しています。

注:次のようなコード

my_new_instance = MyModel.objects.create(my_field='my_field value')

この変更されたcreateメソッドを実行しますが、次のようなコード

my_new_unsaved_instance = MyModel(my_field='my_field value')

しない。


3

オーバーライド__init__()すると、モデルがインスタンス化されたときにコードを実行できます。親のを呼び出すことを忘れないでください__init__()


そうそう、これが答えでした。どうやってこれを見落としたのかわからない。Ignacioに感謝します。
Ground5hark 2010


1

推奨される答えは正しいですが、モデルがUUIDModelから派生している場合、オブジェクトが作成されているかどうかを確認するテストは機能しません。pkフィールドにはすでに値があります。

この場合、これを行うことができます:

already_created = MyModel.objects.filter(pk=self.pk).exists()

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