Django - переопределение метода Model.create()?

Django docs перечисляют только примеры для переопределения save() и delete(). Тем не менее, я бы хотел определить некоторую дополнительную обработку для моих моделей только тогда, когда они созданы. Для тех, кто знаком с Rails, это будет эквивалентно созданию фильтра :before_create. Возможно ли это?

Ответ 1

Переопределение __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)

Ответ 2

пример создания сигнала 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)

вот вдумчивое обсуждение того, лучше ли использовать сигналы или пользовательские методы сохранения http://www.martin-geber.com/thought/2007/10/29/django-signals-vs-custom-save-method/

По-моему, использование сигналов для этой задачи более надежное, более легкое для чтения, но более длительное.

Ответ 3

Переопределение __init__() позволит вам выполнить код при создании экземпляра модели. Не забудьте вызвать родителя __init__().

Ответ 5

Это старый, есть принятый ответ, который работает (Zach's), и более идиоматический (Michael Bylstra's), но так как он все еще первый результат в Google, который большинство людей видит, Я думаю, нам нужно больше:

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)

Дело в следующем:

  • использовать сигналы (подробнее здесь, в официальных документах)
  • используйте метод для nice namespacing (если это имеет смысл)... и я отметил его как @classmethod вместо @staticmethod, потому что, скорее всего, вам придется ссылаться на статические члены класса в коде

Даже чище было бы, если бы у ядра Django был фактический сигнал post_create. (Имхо, если вам нужно передать логический аргумент, чтобы изменить поведение метода, это должно быть 2 метода.)

Ответ 6

Чтобы ответить на вопрос буквально, метод 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()

В этом примере я переопределяю метод метода create Manager, чтобы выполнить некоторую дополнительную обработку до того, как экземпляр действительно будет создан.

ПРИМЕЧАНИЕ: Код, например

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

выполнит этот модифицированный метод create, но код типа

my_new_unsaved_instance = MyModel(my_field='my_field value')

не будет.