Django: как перенаправить сообщение и передать данные сообщения

80

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

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

Также:

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

  • Я не могу показать код, поскольку он принадлежит клиенту.

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

FunLovinCoder
источник
вам действительно нужно отправить перенаправление клиенту, или это можно сделать, просто вызвав функцию и передав ей все данные сообщения?
Мэтью Дж. Моррисон,
Мне нужно изменить URL-адрес в клиентском браузере, так что это единственный способ сделать это.
FunLovinCoder
и вы не можете просто сначала выполнить всю обработку с данными поста, а затем перенаправить постфактум?
Мэтью Дж. Моррисон
У меня аналогичная ситуация, но данные POST либо совпадают, либо не соответствуют существующим данным. Если он совпадает, я получаю идентификатор для этих данных, а затем передаю этот идентификатор скрипту через переменную GET в перенаправлении. Я также сохраняю данные POST в SESSION. Теперь перенаправленная страница загружает данные, на которые ссылается idGET, а также имеет доступ к другим данным, отправленным POST.
Buttle Butkus

Ответы:

57

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

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

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

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

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

дзида
источник
2
Я вижу, что то, что он пытается сделать, может быть действительным, если он пытается обработать просроченный логин, который заставит пользователя войти в систему после отправки формы ... в этом случае он захочет сохранить данные, которые были отправлены, и не заставляют пользователя повторно вводить все после того, как они завершат экран входа в систему.
Мэтью Дж. Моррисон,
Не уверен, понял ли я смысл, но в этом случае операцию входа в систему можно выполнить с помощью первого просмотра с небольшими изменениями кода и без ненужных перенаправлений. Было бы здорово прочитать существующий код, чтобы давать более точные советы.
dzida
Я говорю, что если вы отправляете форму и не вошли в систему, вы будете перенаправлены на форму входа ... в этом сценарии вы потеряете все, что вы отправили. Я согласен с тем, чтобы увидеть некоторый существующий код.
Мэтью Дж. Моррисон,
1
не вам решать, действителен ли вариант использования или нет, я столкнулся с той же ситуацией, для которой перенаправление со свежим POST является идеальным решением с точки зрения простоты и модульности.
Rabih Kodeih
54

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

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

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

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

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

Мэтью Дж. Моррисон
источник
1
Я никогда не использовал сеансы, но я посмотрю на это, спасибо.
FunLovinCoder
1
это не лучшая практика, но все же помогает. Думаю, в этом номере ничего красивее не получится.
Гильерме Давид да Коста
@GuilhermeDaviddaCosta, почему ты говоришь, что это не лучшая практика? Вы можете намекнуть?
Buttle Butkus
потому что хранить слишком много данных в сеансе - не лучшая идея. Но, как я уже сказал, я не могу придумать ничего красивее.
Гильерме Давид да Коста
4
Ну, это зависит от того, где вы храните свою сессию. В последнее время я видел людей, использующих весь сервер с memcached для сеансов и балансировки нагрузки (с использованием циклического перебора) для каждого запроса. Я не хочу давать вам советы, за которые я не могу встать, но я бы сохранил файл как временный и получил бы только ссылку на него в сеансе. Кажется, в наши дни ни у кого не заканчивается барана.
Гильерме Давид да Коста
23

Вам необходимо использовать временное перенаправление 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
Lloeki
источник
Более новые версии Django имеют постоянное перенаправление HttpResponsePermanentRedirect, но не уверен, решает ли он исходную проблему docs.djangoproject.com/en/dev/ref/request-response/…
JiminyCricket
9

использовать 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

Запросы

request.post

Аниш Р.С.
источник
4

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

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

Вы можете использовать рендер и контекст с ним:

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

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

{% If var name %}
 {{ var name }}
{% endif %}
Омид Реза
источник
1

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

В основном у меня была форма 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 маленькая и не такая динамичная.

rkp768
источник
0

Если вы используете перенаправление после обработки 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, разве вас не беспокоит дублирование данных из-за обновления страницы пользователем?

Джек М.
источник
Было бы здорово, если бы такое простое решение работало. Однако мне нужно отобразить подробные результаты после обработки данных. Для этого потребуются сеансы (как предложил Мэтью Дж. Моррисон), не так ли?
FunLovinCoder
1
Вы можете сделать это одним из трех способов. # 1, сохраните данные в базе данных и передайте pkновую запись при перенаправлении. # 2, сохраните данные в cacheсерверной части и снова передайте ключ. # 3, сохраните его в сеансе. Любое из этих действий совершенно нормально для веб-приложения, даже если оно временное. Если данные формы нетривиально поддаются синтаксическому анализу, это также сделало бы систему быстрее, если бы вывод уже был кэширован.
Джек М.