Django: Как перенаправить сообщение и передать данные сообщения - PullRequest
70 голосов
/ 11 июня 2010

При обработке запроса POST в файле Django views.py мне иногда нужно перенаправить его на другой URL-адрес.Этот URL-адрес, на который я перенаправляю, обрабатывается другой функцией из того же файла Django views.py.Есть ли способ сделать это и сохранить исходные данные POST?

ОБНОВЛЕНИЕ: Более подробное объяснение того, почему я хочу это сделать.У меня есть два веб-приложения (назовем их AppA и AppB), которые принимают данные, введенные пользователем в текстовое поле.Когда пользователь нажимает кнопку «Отправить», данные обрабатываются и отображаются подробные результаты.AppA и AppB ожидают разные типы данных.Иногда пользователь по ошибке отправляет данные типа AppB в AppA.Когда это происходит, я хочу перенаправить их в AppB и показать результаты AppB или, по крайней мере, заполнить их данными, введенными в AppA.

Также:

  • Клиенту нужно два отдельных приложения, а не объединять их в одно.

  • Не могупокажите код, который принадлежит клиенту.

ОБНОВЛЕНИЕ 2: Я решил, что KISS - лучший принцип здесь.Я объединил два приложения в одно, что делает вещи проще и надежнее;Я должен быть в состоянии убедить клиента, что это лучший путь.Спасибо за все отличные отзывы.Если бы я собирался поддерживать два приложения, как описано, то я думаю, что сессия была бы способом сделать это - спасибо Мэтью Дж. Моррисону за предложение.Благодаря Дзиде, его комментарии заставили меня задуматься о дизайне и упрощении.

Ответы [ 8 ]

52 голосов
/ 11 июня 2010

Если вы столкнулись с такой проблемой, есть небольшая вероятность, что вам может потребоваться пересмотреть свои проекты.

Это ограничение HTTP, при котором данные POST не могут идти с перенаправлениями.

Можете ли вы описать, что вы пытаетесь достичь, и, возможно, тогда мы можем подумать о каком-то изящном решении.

Если вы не хотите использовать сессии, как предложил Мэтью, вы можете передать параметры POST в GET на новую страницу(обратите внимание на некоторые ограничения, такие как безопасность и максимальная длина параметров GET в строке запроса).

ОБНОВЛЕНИЕ вашего обновления :) Мне странно, что у вас есть 2 веб-приложения, и эти приложения используют одно views.py (я прав?).В любом случае рассмотрите возможность передачи ваших данных из POST в GET в правильное представление (если данные, конечно, не чувствительны).

46 голосов
/ 11 июня 2010

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

Будет ли это работать для того, что вы пытаетесь сделать?

Вот пример кода того, чтоЯ предлагаю: (имейте в виду, что это непроверенный код)

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

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

22 голосов
/ 27 сентября 2010

Вам необходимо использовать HTTP 1.1 Временный редирект (307).

К сожалению, Django redirect() и HTTPResponseRedirect(постоянный) возвращает только 301 или 302. Вы должны реализовать его самостоятельно:

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)

См. также модуль django.http .

Редактировать:

в последних версиях Django, измените iri_to_uri импорт на:

from django.utils.encoding import iri_to_uri
7 голосов
/ 10 мая 2017

использовать requests пакет. Его очень легко реализовать

pip install requests

тогда вы можете вызывать любые URL любым методом и передавать данные

в ваших представлениях запросов на импорт

import requests

для публикации данных следуйте формату

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

, чтобы получить абсолютный URL в представлении django, используйте

request.build_absolute_uri(reverse('view_name'))

Таким образом, код вида django выглядит как

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

, где r - объект ответа с атрибутами status_code и content. r.status_code дает код состояния (в случае успеха это будет 200), а r.content - тело ответа. Существует метод json (r.json()), который преобразует ответ в формат json

запросы

requests.post

2 голосов
/ 05 мая 2016

Просто вызовите ваш новый вид из старого представления, используя тот же объект запроса. Конечно, это не приведет к перенаправлению как таковому, но если все, что вас волнует, это «передача» данных из одного представления в другое, то это должно сработать.
Я протестировал следующий фрагмент, и он работает.

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
1 голос
/ 09 февраля 2019

Я недавно столкнулся с подобной проблемой.

По сути, у меня была форма A, после ее отправки появится другая форма B, которая содержит некоторые результаты + форму. После отправки сообщения B я хотел отобразить некоторое предупреждение для пользователя и оставить пользователя только на B.

Я решил это путем отображения результатов в поле <output>, в B.

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

И я использовал одно и то же представление для A-> B и B-> B. Теперь мне просто нужно было различить, исходит ли запрос от A или B, и отрисовать соответственно.

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})

Но это работает, только если форма B маленькая и не такая динамическая.

1 голос
/ 11 марта 2017

Вы можете использовать render и context вместе с ним:

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

Вы можете получить переменные в шаблоне:

{% If var name %}
 {{ var name }}
{% endif %}
0 голосов
/ 12 июня 2010

Если вы используете перенаправление после обработки POST для AppB, вы можете фактически избежать вызова метода AppB из метода AppA.

Пример:

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/')

Это должно дать прозрачный опыт для конечного пользователя, и клиент, который нанял вас, вероятно, никогда не узнает разницу.

Если вы не перенаправляете после POST, вас не беспокоит дублирование данных из-за того, что пользователь обновляет страницу?

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