Подтвердить что ты не робот

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

Все, у меня проблема с сигналами django.

У меня есть модель Чтобы ускорить отзывчивость загрузок страниц, я разгружаю интенсивную обработку, которую нужно выполнить, посредством вызова второго веб-сервера localhost, который мы запускаем, используя одну и ту же базу данных. Я вижу поведение, когда вызывающий процесс может получить объект, но вызываемый процесс не может. Оба порта 80 и порт [порт] указывают на процессы django, запущенные с той же базы данных.

В models.py

class A(models.Model):
    stuff...

def trigger_on_post_save( sender, instance, create, raw, **keywords):
    #This line works
    A.objects.get( pk=instance.pk )
    #then we call this
    urlopen( r'http://127.0.0.1:[port]' + 
        reverse(some_view_url, args(instance_pk) ).read()

post_save.connect( trigger_on_post_save, A )

В views.py

def some_view_function( request, a_pk ):
    #This line raises an object_not_found exception
    A.objects.get( pk=a_pk )

Кроме того, после вызова urlopen возникает исключение, объект не существует в базе данных. Насколько я понял, post_save был вызван после того, как объект был сохранен и записан в базу данных. Это неверно?

4b9b3361

Ответ 1

Я считаю, что post_save срабатывает после сохранения, но до того, как транзакция будет передана в базу данных. По умолчанию Django фиксирует изменения в базе данных после завершения запроса.

Два возможных решения вашей проблемы:

Честно говоря, вся ваша установка кажется немного противной. Вероятно, вам следует искать Celery для асинхронной очереди задач.

Ответ 2

Мы столкнулись с аналогичной проблемой, и мы закончили использование on_commit callback ( ПРИМЕЧАНИЕ: это возможно только с Django >= 1.9), Итак, вы можете сделать что-то вроде:

from django.db import transaction

class A(models.Model):
    stuff...

def trigger_on_post_save( sender, instance, create, raw, **keywords):
    def on_commit():
        urlopen(r'http://127.0.0.1:[port]' + 
                 reverse(some_view_url, args(instance_pk) ).read()
    transaction.on_commit(on_commit)

post_save.connect( trigger_on_post_save, A )

Идея здесь в том, что вы будете называть свою конечную точку после совершения транзакции, поэтому экземпляр, участвующий в транзакции, будет уже сохранен;).

Ответ 3

Имела ту же проблему при создании новой модели от администратора django. Переопределение метода ModelAdmin.save_model для управления транзакцией вручную.

def save_model(self, request, obj, form, change):
    from django.db import transaction
    with transaction.commit_on_success():
       super(ModelAdmin, self).save_model(request, obj, form, change)

    # write your code here

Ответ 4

Хорошее место для использования декораторов. Существует немного расширенная версия ответа @yoanis-gil:

def on_transaction_commit(func):
    def inner(*args, **kwargs):
        transaction.on_commit(lambda: func(*args, **kwargs))

return inner

@receiver(post_save, sender=A)
@on_transaction_commit
def trigger_on_post_save(sender, **kwargs):
    # Do things here