Использование Django Signals post_save ошибка «save () запрещена, чтобы предотвратить потерю данных, чтобы сделать несохраненный связанный объект« myModel ». - PullRequest
0 голосов
/ 29 апреля 2018

Python 3.6.5 и Django 1.11

Псевдо объяснение:

  • Две модели, с моделью2, использующей модель1 в качестве ForeignKey
  • Администратор для модели1 использует встроенный для модели2
  • В model1 я хочу получить сокращенный URL-адрес и сохранить его в свойстве при появлении новой записи. Для этого нужно сохранить model1, потому что длинный URL (тот, который я хочу сократить) основан на Autoslug.

Соответствующая часть Models.py

class Model1(models.Model):
    name = models.CharField(max_length=100)
    slug = AutoSlugField(populate_from='name', unique=True,
                     null=True, default=None)


class Model2(models.Model):    
    owner = models.ForeignKey(
        'Model1',
        on_delete=models.CASCADE,
    )

Это мой сигнал ...

@receiver(post_save, sender=Model1)
def shorten_url(sender, instance, created, **kwargs):
    if created:
        if not instance.short_url:
            url_short = url_shorten(instance.get_absolute_url())
            instance.short_url = url_short
            post_save.disconnect(shorten_url, sender=sender)
            instance.save()
            post_save.connect(shorten_url, sender=sender)
            return instance
        else:
            post_save.disconnect(shorten_url, sender=sender)
            instance.save()
            post_save.connect(shorten_url, sender=sender)
            return instance

Разъединение, подключение - это предотвращение зацикливания, я не уверен на 100%, что это тоже правильно, но без него я вижу вызовы, чтобы сократить URL снова и снова ...

Проблема, которую я сейчас пытаюсь решить, заключается в том, что я получаю ошибку save() prohibited to prevent data loss to unsaved related object 'model1' когда я звоню save ().

Вот трассировка:

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
41.             response = get_response(request)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/core/handlers/base.py" in _legacy_get_response
249.             response = self._get_response(request)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
187.                 response = self.process_exception_by_middleware(e, request)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/admin/options.py" in wrapper
551.                 return self.admin_site.admin_view(view)(*args, **kwargs)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/utils/decorators.py" in _wrapped_view
149.                     response = view_func(request, *args, **kwargs)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
57.         response = view_func(request, *args, **kwargs)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/admin/sites.py" in inner
224.             return view(request, *args, **kwargs)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/admin/options.py" in add_view
1508.         return self.changeform_view(request, None, form_url, extra_context)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/utils/decorators.py" in _wrapper
67.             return bound_func(*args, **kwargs)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/utils/decorators.py" in _wrapped_view
149.                     response = view_func(request, *args, **kwargs)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/utils/decorators.py" in bound_func
63.                 return func.__get__(self, type(self))(*args2, **kwargs2)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/admin/options.py" in changeform_view
1408.             return self._changeform_view(request, object_id, form_url, extra_context)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/admin/options.py" in _changeform_view
1449.                 self.save_related(request, form, formsets, not add)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/admin/options.py" in save_related
1003.             self.save_formset(request, form, formset, change=change)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/admin/options.py" in save_formset
991.         formset.save()

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/forms/models.py" in save
649.         return self.save_existing_objects(commit) + self.save_new_objects(commit)

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/forms/models.py" in save_new_objects
783.             self.new_objects.append(self.save_new(form, commit=commit))

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/forms/models.py" in save_new
927.             obj.save()

File "/home/username/.virtualenvs/project/lib/python3.6/site-packages/django/db/models/base.py" in save
762.                         "unsaved related object '%s'." % field.name

Exception Type: ValueError at /admin/wa/model1/add/
Exception Value: save() prohibited to prevent data loss due to unsaved related object 'model1'.

Я предполагаю, что это потому, что я post_save на model1 и у меня есть строки model2, ожидающие ключ model1, ошибка не говорит об этом. Если бы в сообщении об ошибке было указано model2, это было бы для меня более логично, но это не так.

При просмотре строки 762 base.py, которая вызывает ошибку, он также, похоже, обрабатывает этот случай несохраненного (без PK) объекта, но опять же ... Я пост_сэйв здесь, не так ли?

Еще одно обновление

Пытаясь решить эту проблему дальше, я отправил форму администратора без данных в разделе встроенной формы (т.е. без данных в Model2). Когда я делаю это, я получаю две записи в Model1, каждая из которых не содержит PK ... PK == Нет. ничего себе.

Спасибо за помощь!

1 Ответ

0 голосов
/ 01 мая 2018

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

В моем случае, несколько дней назад на моем компьютере разработчика я перешел с SQLITE3 на PostgreSQL в ожидании того же в рабочей среде. Тем не менее, моя процедура была ошибочной, и у меня была прекрасно работающая база данных READ, но ни один из идентификаторов не генерировался автоматически при записи.

В моем случае я использовал PGLOADER для загрузки данных. Не делай этого. Используйте инструменты Django для dumpdata и loaddata.

...