Django: ¿Cómo redirecciono una publicación y paso los datos de la publicación?

80

Al procesar una solicitud POST en el archivo Django views.py, a veces necesito redirigirla a otra URL. Esta URL a la que estoy redirigiendo es manejada por otra función en el mismo archivo Django views.py. ¿Hay alguna forma de hacer esto y mantener los datos POST originales?

ACTUALIZACIÓN: Más explicación de por qué quiero hacer esto. Tengo dos aplicaciones web (llamémoslas AppA y AppB) que aceptan datos ingresados ​​en un campo de texto por el usuario. Cuando el usuario hace clic en enviar, los datos se procesan y se muestran los resultados detallados. AppA y AppB esperan diferentes tipos de datos. A veces, un usuario publica por error datos de tipo AppB en AppA. Cuando esto sucede, quiero redirigirlos a AppB y mostrar los resultados de AppB o al menos llenarlos con los datos que ingresaron en AppA.

También:

  • El cliente quiere dos aplicaciones separadas en lugar de combinarlas en una sola.

  • No puedo mostrar el código porque pertenece a un cliente.

ACTUALIZACIÓN 2: He decidido que KISS es el mejor principio aquí. He combinado las dos aplicaciones en una que hace las cosas más simples y sólidas; Debería poder convencer al cliente de que también es la mejor manera de hacerlo. Gracias por todos los excelentes comentarios. Si tuviera que mantener dos aplicaciones como se describe, creo que las sesiones serían la forma de hacerlo, gracias a Matthew J Morrison por sugerir eso. Gracias a Dzida porque sus comentarios me hicieron pensar en el diseño y la simplificación.

FunLovinCoder
fuente
¿Realmente necesita enviar una redirección al cliente, o es algo que se puede hacer simplemente llamando a una función y pasándole todos los datos de la publicación?
Matthew J Morrison
Necesito cambiar la URL en el navegador del cliente, así que esta es la única forma en que puedo hacerlo.
FunLovinCoder
y no puede simplemente hacer todo el procesamiento con los datos de la publicación primero y luego redirigir después del hecho?
Matthew J Morrison
Tengo una situación similar, pero los datos publicados en POST coinciden o no con los datos existentes. Si coincide, obtengo la identificación de esos datos, luego paso esa identificación al script a través de la variable GET en la redirección. También guardo los datos POST en SESSION. Ahora la página redirigida carga los datos a los que hace referencia iden GET, y también tiene acceso a otros datos enviados por POST.
Buttle Butkus

Respuestas:

57

Si se enfrentó a tal problema, existe una pequeña posibilidad de que deba revisar sus diseños.

Esta es una restricción de HTTP que los datos POST no pueden ir con redirecciones.

¿Puede describir lo que está tratando de lograr y tal vez entonces podamos pensar en una buena solución?

Si no desea usar sesiones como sugirió Matthew, puede pasar los parámetros POST en GET a la nueva página (considere algunas limitaciones como la seguridad y la longitud máxima de los parámetros GET en la cadena de consulta).

ACTUALIZAR a su actualización :) Me parece extraño que tenga 2 aplicaciones web y esas aplicaciones usen una views.py (¿verdad?). De todos modos, considere pasar sus datos de POST en GET a la vista adecuada (en caso de que los datos no sean confidenciales, por supuesto).

dzida
fuente
2
Puedo ver que lo que está tratando de hacer podría ser válido si está tratando de manejar un inicio de sesión caducado que obligará al usuario a iniciar sesión después de enviar un formulario ... en ese caso, querrá retener el datos que se enviaron y no obligar al usuario a volver a ingresar todo después de completar la pantalla de inicio de sesión.
Matthew J Morrison
No estoy seguro si entendí el punto, pero en este caso la operación de inicio de sesión se puede realizar en la primera vista con poca modificación de código y sin realizar redireccionamientos innecesarios. Sería genial leer el código existente para hacer consejos más precisos.
dzida
Estoy diciendo que si envía un formulario y no ha iniciado sesión, se le redirigirá a un formulario de inicio de sesión ... en ese escenario, perderá lo que haya enviado. Estoy de acuerdo en poder ver algún código existente.
Matthew J Morrison
1
No depende de usted decidir si el caso de uso es válido o no, me enfrento a la misma situación para la que una redirección con POST fresco es la solución perfecta en términos de simplicidad y modularidad.
Rabih Kodeih
54

Creo que la forma en que probablemente manejaría esta situación sería guardar los datos de la publicación en la sesión y luego eliminarlos cuando ya no los necesite. De esa manera puedo acceder a los datos de la publicación original después de una redirección, aunque esa publicación ya no esté.

¿Funcionará eso para lo que intentas hacer?

Aquí hay una muestra de código de lo que sugiero: (tenga en cuenta que este es un código no probado)

def some_view(request):
    #do some stuff
    request.session['_old_post'] = request.POST
    return HttpResponseRedirect('next_view')

def next_view(request):
    old_post = request.session.get('_old_post')
    #do some stuff using old_post

Otra cosa a tener en cuenta ... si está haciendo esto y también cargando archivos, yo no lo haría de esta manera.

Matthew J. Morrison
fuente
1
Nunca he usado sesiones, pero echaré un vistazo a eso gracias.
FunLovinCoder
1
esta no es la mejor práctica, pero de todos modos ayuda. Supongo que para este número no conseguiremos nada más bonito.
Guilherme David da Costa
@GuilhermeDaviddaCosta ¿por qué dices que no es la mejor práctica? ¿Puedes darnos una pista?
Buttle Butkus
porque no parece muy buena idea almacenar demasiados datos en la sesión. Pero como también dije, no puedo pensar en nada más bonito.
Guilherme David da Costa
4
Bueno, eso depende de dónde guarde su sesión. Últimamente he visto personas que usan un servidor completo con memcached para sesiones y balance de carga (usando round robin) en cada solicitud. No quiero darte un consejo que no pueda defender, pero guardaría el archivo como temporal y solo obtendría un enlace en la sesión. Parece que nadie se está quedando sin ram en estos días.
Guilherme David da Costa
23

Necesita utilizar un redireccionamiento temporal HTTP 1.1 (307).

Desafortunadamente, Django redirect()y HTTPResponseRedirect (permanente) devuelven solo un 301 o 302. Tienes que implementarlo tú mismo:

from django.http import HttpResponse, iri_to_uri
class HttpResponseTemporaryRedirect(HttpResponse):
    status_code = 307

    def __init__(self, redirect_to):
        HttpResponse.__init__(self)
        self['Location'] = iri_to_uri(redirect_to)

Consulte también el módulo django.http .

Editar:

en versiones recientes de Django, cambie la iri_to_uriimportación a:

from django.utils.encoding import iri_to_uri
Lloeki
fuente
Las versiones más nuevas de Django tienen una redirección permanente HttpResponsePermanentRedirect pero no estoy seguro de si resuelve el problema original docs.djangoproject.com/en/dev/ref/request-response/…
JiminyCricket
9

requestspaquete de uso Es muy fácil de implementar

pip install requests

entonces puedes llamar a cualquier URL con cualquier método y transferir datos

en sus vistas solicitudes de importación

import requests

para publicar datos, siga el formato

r = requests.post('http://yourdomain/path/', data = {'key':'value'})

para obtener la URL absoluta en la vista de django, use

request.build_absolute_uri(reverse('view_name'))

Por lo tanto, el código de vista de django se ve así

r = requests.post(
            request.build_absolute_uri(reverse('view_name')), 
            data = {'key':'value'}
    )

donde res el objeto de respuesta con status_codey contentatributo. r.status_codeda el código de estado (en caso de éxito, será 200) y r.contentda el cuerpo de la respuesta. Hay un método json ( r.json()) que convertirá la respuesta al formato json

peticiones

request.post

Aneesh RS
fuente
4

Simplemente llame a su nueva vista desde su vista anterior usando el mismo objeto de solicitud. Por supuesto, no resultará en una redirección como tal, pero si todo lo que le importa es 'transferir' datos de una vista a otra, entonces debería funcionar.
Probé el siguiente fragmento y funciona.

from django.views.generic import View

class MyOldView(View):
    def post(self, request):
        return MyNewView().post(request)

class MyNewView(View):
    def post(self, request):
        my_data = request.body
        print "look Ma; my data made it over here:", my_data
Komu
fuente
1

Puede usar render y contexto con él:

Render(request,"your template path",        {'vad name' : var value}

Puede recibir vars en la plantilla:

{% If var name %}
 {{ var name }}
{% endif %}
Omid reza
fuente
1

Recientemente me enfrenté a un problema similar.

Básicamente tenía un formulario A, al enviarlo aparecería otro formulario B, que contiene algunos resultados + un formulario. Al enviar B, quería mostrar alguna alerta al usuario y mantener al usuario solo en B.

La forma en que resolví esto es mostrando los resultados en un <output>campo, en B.

<output name="xyz" value="xyz">{{xyz}}</output>

Y usé la misma vista para A-> B y B-> B. Ahora solo tenía que distinguir si la solicitud proviene de A o B y renderizar en consecuencia.

def view1(request):
    if "xyz" in request.POST:
        # request from B
        # do some processing
        return render(request, 'page.html', {"xyz":request.POST["xyz"]})
    else:
        # request from A
        res = foo() # some random function
        return render(request, 'page.html', {"xyz":res})

Pero esto solo funciona si la forma B es pequeña y no tan dinámica.

rkp768
fuente
0

Si está utilizando una redirección después de procesar el POST AppB, puede salirse con la suya llamando al AppBmétodo desde el AppAmétodo.

Un ejemplo:

def is_appa_request(request):
    ## do some magic.
    return False or True
is_appb_request = is_appa_request

def AppA(request):
    if is_appb_request(request):
       return AppB(request)
    ## Process AppA.
    return HttpResponseRedirect('/appa/thank_you/')

def AppB(request):
    if is_appa_request(request):
       return AppA(request)
    ## Process AppB.
    return HttpResponseRedirect('/appb/thank_you/')

Esto debería generar una experiencia transparente para el usuario final, y es probable que el cliente que lo contrató nunca sepa la diferencia.

Si no está redireccionando después del POST, ¿no le preocupa la duplicación de datos debido a que el usuario actualiza la página?

Jack M.
fuente
Sería genial si una solución simple como esta funcionara. Sin embargo, necesito mostrar resultados detallados después de procesar los datos. Esto requeriría sesiones (como lo propone Matthew J. Morrison) ¿no es así?
FunLovinCoder
1
Puede hacerlo de tres formas. # 1, almacene los datos en la base de datos y pase el pkde la nueva entrada cuando redirija. # 2, almacene los datos en el cachebackend y vuelva a pasar la clave. # 3, guárdelo en la sesión. Cualquiera de estos es perfectamente normal para una aplicación web, incluso si es temporal. Si los datos del formulario no son triviales de analizar, también haría que el sistema fuera más rápido si la salida ya estaba almacenada en caché.
Jack M.