Django docs перечисляют только примеры для переопределения save()
и delete()
. Тем не менее, я бы хотел определить некоторую дополнительную обработку для моих моделей только тогда, когда они созданы. Для тех, кто знаком с Rails, это будет эквивалентно созданию фильтра :before_create
. Возможно ли это?
Django - переопределение метода Model.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__()
.
Ответ 4
Вы можете переопределить метод create с помощью настраиваемого менеджера или добавить класс класса в класс модели. https://docs.djangoproject.com/en/1.11/ref/models/instances/#creating-objects
Ответ 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')
не будет.