Django: Як мені перенаправити повідомлення та передати дані повідомлення?


80

Під час обробки запиту POST у файлі Django views.py мені іноді потрібно перенаправити його на іншу URL-адресу. Ця URL-адреса, на яку я переспрямовую, обробляється іншою функцією у тому ж файлі Django views.py. Чи є спосіб зробити це і зберегти вихідні дані POST?

ОНОВЛЕННЯ: Більше пояснення, чому я хочу це зробити. У мене є дві веб-програми (назвемо їх AppA та AppB), які приймають дані, введені користувачем у текстове поле. Коли користувач натискає кнопку подати, дані обробляються і відображаються докладні результати. AppA та AppB очікують різні типи даних. Іноді користувач помилково передає дані типу AppB до AppA. Коли це трапляється, я хочу перенаправити їх на AppB і показати результати AppB або, принаймні, заповнити їх даними, які вони ввели в AppA.

Також:

  • Клієнт хоче дві окремі програми, а не поєднувати їх лише в одній.

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

ОНОВЛЕННЯ 2: Я вирішив, що KISS - найкращий принцип тут. Я об’єднав ці два додатки в один, що робить речі простішими та надійнішими; Я повинен бути в змозі переконати клієнта, що це також найкращий спосіб піти. Дякуємо за всі чудові відгуки. Якби я збирався підтримувати два додатки, як описано, то, я думаю, сесії були б способом зробити це - дякую Меттью Дж. Моррісону за пропозицію. Завдяки Дзіді, коли його коментарі змусили мене задуматися про дизайн та спрощення.


вам дійсно потрібно надіслати переадресацію клієнту, чи це щось можна зробити, просто викликавши функцію і передавши їй усі дані публікації?
Matthew J Morrison

Мені потрібно змінити URL-адресу в браузері клієнта, тому це єдиний спосіб зробити це.
FunLovinCoder

і ти не можеш просто спочатку виконати всю обробку з даними повідомлення, а потім перенаправити?
Matthew J Morrison,

У мене схожа ситуація, але дані POST'і або відповідають, або не відповідають існуючим даним. Якщо він збігається, я отримую ідентифікатор цих даних, а потім передаю цей ідентифікатор сценарію через змінну GET у перенаправленні. Я також зберігаю дані POST у SESSION. Тепер переспрямована сторінка завантажує дані, на які посилається idGET, а також має доступ до інших даних, поданих POST.
Buttle Butkus

Відповіді:


57

Якщо ви зіткнулися з такою проблемою, є невелика ймовірність, що вам може знадобитися переглянути свій дизайн.

Це обмеження HTTP, що дані POST не можуть поєднуватися з переспрямуваннями.

Чи можете ви описати, що ви намагаєтесь досягти, і, можливо, тоді ми можемо подумати про якесь акуратне рішення.

Якщо ви не хочете використовувати сеанси, як запропонував Метью, ви можете передати параметри POST у GET на нову сторінку (врахуйте деякі обмеження, такі як безпека та максимальна довжина параметрів GET у рядку запиту).

ОНОВИТИ до свого оновлення :) Мені здається дивним, що у вас є 2 веб-програми, і ці програми використовують один view.py (я маю рацію?). У будь-якому випадку розгляньте можливість передачі ваших даних із POST у GET до належного перегляду (якщо дані, звичайно, не є чутливими).


2
Я бачу, що те, що він намагається зробити, може бути дійсним, якщо він намагається обробити термін дії входу, який змусить користувача ввійти після подання форми ... у такому випадку він захоче зберегти дані, які були подані, і не змушують користувача повторно вводити все після того, як вони заповнять екран входу.
Matthew J Morrison,

Не впевнений, що я зрозумів, але в цьому випадку операцію входу можна виконати шляхом першого перегляду з невеликою зміною коду і без зайвих перенаправлення. Було б чудово прочитати існуючий код, щоб отримати більш точні поради.
dzida

Я кажу, якщо ви надішлете форму, і ви не ввійшли в систему, ви отримаєте перенаправлення у форму для входу ... у цьому випадку ви втратите все, що було подано вами. Я погоджуюсь з тим, що я можу бачити якийсь існуючий код.
Matthew J Morrison,

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
це не найкраща практика, але все одно допомагає. Я думаю, для цього випуску ми не отримаємо нічого красивішого.
Guilherme David da Costa

@GuilhermeDaviddaCosta, чому ви вважаєте, що це не найкраща практика? Чи можете ви дати нам підказку?
Buttle Butkus

оскільки здається не дуже хорошою ідеєю зберігати занадто багато даних під час сеансу. Але, як я вже сказав, я не можу придумати нічого гарнішого.
Guilherme David da Costa

4
Ну, це залежить від того, де ви зберігаєте сеанс. Останнім часом я бачу людей, які використовують цілий сервер з memcached для сеансів та балансом навантаження (за допомогою кругового пошуку) кожного запиту. Я не хочу давати вам поради, за які я не можу відстоятись, але я б зберіг файл як тимчасовий і отримав лише посилання на нього на сесії. Здається, в ці дні ніхто нічого не закінчує.
Guilherme David da Costa

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

Новіші версії 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

запитів

запити. пост


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

Але це працює лише в тому випадку, якщо форма В мала і не така динамічна.


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, зберігайте його в сесії. Будь-яке з них є цілком нормальним для веб-програми, навіть якщо це тимчасово. Якщо дані форми нетривіальні для аналізу, це також зробить систему швидшою, якщо вихідні дані вже були кешовані.
Jack M.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.