Выполнить код в Django после того, как ответ был отправлен клиенту - PullRequest
16 голосов
/ 30 ноября 2010

В моем приложении Django я хочу отслеживать, был ли ответ успешно отправлен клиенту. Мне хорошо известно, что в протоколе без установления соединения, таком как HTTP, нет «водонепроницаемого» способа гарантировать, что клиент получил (и отобразил) ответ, так что это не будет критически важной функцией, но все же я хочу сделать это на самое позднее возможное время Ответ не будет HTML, поэтому любые обратные вызовы от клиента (с использованием тегов Javascript или IMG и т. Д.) Невозможны.

"Последний" хук, который я могу найти, - это добавление собственного промежуточного программного обеспечения, реализующего process_response, в первой позиции списка промежуточного программного обеспечения, но, насколько я понимаю, это выполняется до того, как фактический ответ будет создан и отправлен клиенту. Есть ли какие-либо перехватчики / события в Django для выполнения кода после успешной отправки ответа?

Ответы [ 3 ]

19 голосов
/ 30 ноября 2010

Метод, который я сейчас использую, использует подкласс HttpResponse:

from django.template import loader
from django.http import HttpResponse

# use custom response class to override HttpResponse.close()
class LogSuccessResponse(HttpResponse):

    def close(self):
        super(LogSuccessResponse, self).close()
        # do whatever you want, this is the last codepoint in request handling
        if self.status_code == 200:
            print('HttpResponse successful: %s' % self.status_code)

# this would be the view definition
def logging_view(request):
    response = LogSuccessResponse('Hello World', mimetype='text/plain')
    return response

Читая код Django, я очень уверен, что HttpResponse.close () - это последняя точка для внедрения кода в обработку запросов. Я не уверен, что действительно есть случаи ошибок, которые обрабатываются этим методом лучше, чем упомянутые выше, поэтому я пока оставляю вопрос открытым.

Причины, по которым я предпочитаю этот подход другим, упомянутым в ответе lazerscience, заключаются в том, что он может быть настроен только в представлении и не требует установки промежуточного программного обеспечения. Использование сигнала request_finished, с другой стороны, не позволило бы мне получить доступ к объекту ответа.

2 голосов
/ 13 марта 2019

Если вам нужно сделать это много, полезный трюк состоит в том, чтобы иметь специальный класс ответа, такой как:

class ResponseThen(Response):
    def __init__(self, data, then_callback, **kwargs):
        super().__init__(data, **kwargs)
        self.then_callback = then_callback

    def close(self):
        super().close()
        self.then_callback()

def some_view(request):
    # ...code to run before response is returned to client

    def do_after():
        # ...code to run *after* response is returned to client

    return ResponseThen(some_data, do_after, status=status.HTTP_200_OK)

... помогает, если вам нужно быстрое / хакерское решение «запустить и забыть», не удосужившись интегрировать правильную очередь задач или отделить отдельный микросервис от вашего приложения.

1 голос
/ 30 ноября 2010

Полагаю, когда вы говорите о промежуточном программном обеспечении, вы думаете о методе process_request промежуточного программного обеспечения, но есть также метод process_response , который вызывается при возврате объекта HttpResponse. Я думаю, это будет последний момент, когда вы сможете найти крючок, который вы можете использовать.

Кроме того, также подается сигнал request_finished .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...