В методе custom save() модели django, как вы должны идентифицировать новый объект?

Я хочу вызвать специальное действие в методе save() объекта модели Django, когда я сохраняю новую запись (не обновляя существующую запись).

Является ли проверка (self.id!= None) необходимой и достаточной, чтобы гарантировать самозапись, является новой и не обновляется? Любые особые случаи, которые это может не учитывать?

Ответ 1

self.pk is None:

возвращает значение True в новом объекте Model, если у объекта нет UUIDField как его primary_key.

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

Ответ 2

Альтернативный способ проверки self.pk мы можем проверить self._state модели

self._state.adding is True создает

self._state.adding is False обновление

Я получил это с этой страницы

Ответ 3

Проверка self.id предполагает, что id является основным ключом для модели. Более общий способ - использовать pk shortcut.

is_new = self.pk is None

Ответ 4

Проверка self.pk == None не, чтобы определить, будет ли объект вставлен или обновлен в базе данных.

Django O/RM имеет особенно неприятный хак, который в основном проверяет, есть ли что-то в позиции PK, и если это так, UPDATE, в противном случае сделайте INSERT (это оптимизируется для INSERT, если PK - None).

Причина, по которой это необходимо, заключается в том, что вам разрешено устанавливать PK при создании объекта. Хотя это не так часто, когда у вас есть столбец последовательностей для первичного ключа, это не выполняется для других типов поля первичного ключа.

Если вы действительно хотите знать, что вам нужно делать то, что делает O/RM, и посмотреть в базе данных.

Конечно, у вас есть конкретный случай в вашем коде, и для этого вполне вероятно, что self.pk == None сообщает вам все, что вам нужно знать, но это не общее решение.

Ответ 6

Проверьте флажок self.id и force_insert.

if not self.pk or kwargs.get('force_insert', False):
    self.created = True

# call save method.
super(self.__class__, self).save(*args, **kwargs)

#Do all your post save actions in the if block.
if getattr(self, 'created', False):
    # So something
    # Do something else

Это удобно, потому что ваш вновь созданный объект (self) имеет значение pk

Ответ 7

Я очень опаздываю на этот разговор, но у меня возникла проблема с заполнением self.pk, когда у него есть связанное с ним значение по умолчанию.

Способ, которым я обходился, заключается в добавлении поля date_created в модель

date_created = models.DateTimeField(auto_now_add=True)

Отсюда вы можете пойти

created = self.date_created is None

Ответ 8

скорее используйте pk вместо id:

if not self.pk:
  do_something()

Ответ 9

Для решения, которое также работает, даже если у вас есть UUIDField как первичный ключ (который, как отмечали другие, не None, если вы просто переопределяете save), вы можете подключиться к Django post_save. Добавьте это в свои models.py:

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

@receiver(post_save, sender=MyModel)
def mymodel_saved(sender, instance, created, **kwargs):
    if created:
        # do extra work on your instance, e.g.
        # instance.generate_avatar()
        # instance.send_email_notification()
        pass

Этот обратный вызов блокирует метод save, поэтому вы можете делать такие вещи, как триггерные уведомления, или обновлять модель до того, как ваш ответ будет отправлен обратно по каналу, независимо от того, используете ли вы формы или структуру Django REST для вызовов AJAX, Конечно, используйте ответственно и выгружайте тяжелые задачи в очередь заданий вместо того, чтобы ждать ваших пользователей:)

Ответ 10

Это обычный способ сделать это.

идентификатор будет передан при первом сохранении в db

Ответ 11

Будет ли это работать для всех вышеперечисленных сценариев?

if self.pk is not None and <ModelName>.objects.filter(pk=self.pk).exists():
...

Ответ 12

Чтобы узнать, обновляетесь ли вы или вставляете объект (данные), используйте self.instance.fieldname в своей форме. Определите чистую функцию в своей форме и проверьте, соответствует ли текущая запись значения предыдущей, если нет, то вы ее обновляете.

self.instance и self.instance.fieldname сравните с новым значением