La documentación de Django para el estado request_finished proporciona la clase, no la instancia (no estoy seguro de por qué, hubiera sido más útil proporcionar la instancia). https://docs.djangoproject.com/en/1.9/ref/signals/#request-finished
Por lo tanto, la señal solo le informa que la solicitud ha finalizado, pero no la solicitud ni ningún detalle de la misma. Tienes 2 opciones para obtener la solicitud. Uno, que se ha mencionado, es almacenar la solicitud en el almacenamiento local de subprocesos en un middleware.
Aquí hay un ejemplo que almacena la solicitud. Pero puede usarlo para almacenar funciones que serán llamadas al final.
import collections
import threading
import structlog
from django.utils.cache import patch_vary_headers
logger = structlog.get_logger()
thread_locals = threading.local()
def get_current_request():
"""
This will return the current request object
but if the response has been returned the request
object will be cleaned up
"""
return getattr(thread_locals, 'request', None)
def request_queue(func, func_id=None, *args, **kwargs):
"""
Helper function to queue up a function
and arguments to be run at the end of the request
if no request, will run straight away
Usage:
request_queue(function_to_run, args=(args1, args2), kwargs={'key':'value'})
"""
request = get_current_request()
if not request:
# run the func
func(*args, **kwargs)
return
# else
# use the supplied id if given
if not func_id:
# otherwise use the memory address
func_id = id(func)
# store the func and arguments as a tuple under the func id
request.queue[func_id] = (func, args, kwargs)
class RequestQueueMiddleware(object):
"""
Use this middleware to get access to the request object
and to use it to queue functions to run
"""
def process_request(self, request):
thread_locals.request = request
# each request gets a new queue
request.queue = collections.OrderedDict()
def process_exception(self, request, exception):
self.process_queue(request)
self.cleanup()
def process_response(self, request, response):
self.process_queue(request)
self.cleanup()
return response
def cleanup(self):
try:
del thread_locals.request
except AttributeError:
pass
def process_queue(self, request):
if not request:
request = get_current_request()
if request and hasattr(request, 'queue'):
for (func, args, kwargs) in getattr(request, 'queue', {}).itervalues():
func(*args, **kwargs)
del request.queue
La función get_current_request
pueden ser importados y utilizados en cualquier otro método cuando necesite acceder a la solicitud actual.
La función request_queue
le permite poner en cola una función y los argumentos que se ejecutarán. Una característica es que puede poner en cola una función costosa muchas veces y solo se ejecutará una vez.
Por lo tanto, en su controlador request_finished
puede llamar al get_current_request
para obtener la solicitud actual. Pero en la implementación anterior, deberá eliminar el código de limpieza. No sé si se perderá el mantenimiento del objeto de solicitud en el almacenamiento local de subprocesos.
La otra opción que no requiere ningún middleware es inspeccionar los marcos de la pila hasta que encuentre la solicitud.
def get_request():
"""Walk up the stack, return the nearest first argument named "request"."""
frame = None
try:
for f in inspect.stack()[1:]:
frame = f[0]
code = frame.f_code
if code.co_varnames and code.co_varnames[0] == "request":
return frame.f_locals['request']
finally:
del frame
Si tiene cualquier otra variable llamados solicitud se romperá. Podría ser adaptado para verificar el tipo también.
No estoy seguro de que pueda hacerlo. ¿Estás tratando de mirar la palabra clave arguments dict? Si solo desea registrar alguna información en cada solicitud, debe considerar usar el marco de Middleware http://bit.ly/axVgOj. – buckley
'sender' es la clase de modelo, no una instancia. Si se proporcionan datos de instancia, lo encontrará en '** kwargs', sin embargo' request_finished' no incluye ningún dato de instancia. Es posible que pueda usar la señal 'post_save' en su lugar. Si tiene una tarea que consume mucho tiempo y no desea que la solicitud espere antes de finalizar, ejecútela en un nuevo hilo, diga 'thread.start_new_thread (kwargs.get (" instance "). Do_something_time_consuming,())'. – henrikstroem
Los documentos en django dicen que es una clase y no una instancia. https://docs.djangoproject.com/en/1.9/ref/signals/#request-finished ¿Por qué se ha aceptado una respuesta completamente incorrecta? – dalore