Джанго - Переопределение метода Model.create ()? - PullRequest
67 голосов
/ 22 февраля 2010

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

Ответы [ 7 ]

133 голосов
/ 22 февраля 2010

Переопределение __init__() приведет к выполнению кода всякий раз, когда создается представление объекта на python. Я не знаю rails, но фильтр :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)
21 голосов
/ 27 сентября 2012

пример того, как создать сигнал 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/

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

14 голосов
/ 11 августа 2017

Это старый, имеет принятый ответ, который работает (Зак), и более идиоматический ответ (Майкл Билстра), но так как это все еще первый результат в 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)

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

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

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

6 голосов
/ 07 августа 2017

Если ответить буквально на вопрос, метод 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 голосов
/ 01 сентября 2016

Вы можете переопределить метод create с помощью собственного менеджера или добавить метод класса в класс модели. https://docs.djangoproject.com/en/1.11/ref/models/instances/#creating-objects

3 голосов
/ 22 февраля 2010

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

1 голос
/ 26 октября 2018

Предпочтительный ответ правильный, но проверка того, создается ли объект, не работает, если ваша модель наследуется от UUIDModel. Поле pk уже будет иметь значение.

В этом случае вы можете сделать это:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...