2010-02-21 4 views
51

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

ответ

102

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

Я действительно нашел решение, используя сигналы: http://docs.djangoproject.com/en/dev/topics/signals/ (сигнал pre_save, в частности). Однако это представляется гораздо более прагматичным решением. Огромное спасибо. – ground5hark

+0

красивый взлом. Я бы предпочел переопределить метод create, так как я хотел бы добавить вызов logging.info после создания нового объекта. Вызвав его раньше, и у вас есть вероятность того, что вызов родительского метода завершится неудачно ... – philgo20

+3

Предполагаю, вы имеете в виду переопределение метода-менеджера 'create'? Это интересное решение, но оно не будет работать в случаях, когда объект создается с помощью 'Object (** kwargs) .save()' или любой другой вариант. – Zach

4

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

+0

А да, это был ответ. Не знаю, как я это забыл. Спасибо Игнасио. – ground5hark

17

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

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

+0

Это предпочтительный способ вместо возиться с внутренними объектами, однако, если вы вносите изменения в рассматриваемую модель, а не просто создаете другую в приведенном выше примере, ** не забудьте вызвать 'instance.save()' **. Таким образом, в этом случае также наблюдается снижение производительности, поскольку в базу данных будет один запрос INSERT и один UPDATE. –

1

Чтобы ответить на вопрос буквально, метод 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 Управляющего сделать некоторую дополнительную обработку, прежде чем экземпляр фактически создается.

Примечание: код как

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

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

my_new_unsaved_instance = MyModel(my_field='my_field value')

не будет.

3

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

Дело заключается в следующем:

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

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

Смежные вопросы