Django: Làm cách nào để chuyển hướng một bài đăng và chuyển dữ liệu bài đăng


80

Khi xử lý một yêu cầu ĐĂNG trong tệp Django views.py, đôi khi tôi cần chuyển hướng nó đến một url khác. Url mà tôi đang chuyển hướng đến này được xử lý bởi một chức năng khác trong cùng một tệp Django views.py. Có cách nào để thực hiện việc này và duy trì dữ liệu POST ban đầu không?

CẬP NHẬT: Giải thích thêm về lý do tại sao tôi muốn làm điều này. Tôi có hai ứng dụng web (chúng ta hãy gọi chúng là AppA và AppB) chấp nhận dữ liệu do người dùng nhập vào trường văn bản. Khi người dùng nhấp vào gửi, dữ liệu được xử lý và kết quả chi tiết được hiển thị. AppA và AppB mong đợi các loại dữ liệu khác nhau. Đôi khi người dùng đăng nhầm dữ liệu loại AppB lên AppA. Khi điều này xảy ra, tôi muốn chuyển hướng họ đến AppB và hiển thị kết quả AppB hoặc ít nhất là đã điền vào dữ liệu họ đã nhập vào AppA.

Cũng thế:

  • Khách hàng muốn hai ứng dụng riêng biệt hơn là kết hợp chúng thành một.

  • Tôi không thể hiển thị mã vì nó thuộc về một khách hàng.

CẬP NHẬT 2: Tôi đã quyết định rằng KISS là nguyên tắc tốt nhất ở đây. Tôi đã kết hợp hai ứng dụng thành một ứng dụng giúp mọi thứ đơn giản hơn và mạnh mẽ hơn; Tôi cũng có thể thuyết phục khách hàng đó là cách tốt nhất. Cảm ơn vì tất cả những phản hồi tuyệt vời. Nếu tôi định duy trì hai ứng dụng như đã mô tả thì tôi nghĩ các phiên sẽ là cách để làm điều này - cảm ơn Matthew J Morrison đã gợi ý điều đó. Cảm ơn Dzida vì những nhận xét của anh ấy đã khiến tôi suy nghĩ về thiết kế và đơn giản hóa.


bạn có thực sự cần gửi chuyển hướng đến máy khách không hay đây là điều có thể thực hiện bằng cách chỉ gọi một hàm và chuyển tất cả dữ liệu bài đăng cho nó?
Matthew J Morrison

Tôi cần thay đổi url trên trình duyệt của khách hàng, vì vậy đây là cách duy nhất tôi có thể làm điều đó.
FunLovinCoder

và bạn không thể chỉ thực hiện tất cả các xử lý với dữ liệu bài đăng trước, rồi chuyển hướng sau khi thực tế?
Matthew J Morrison

Tôi gặp trường hợp tương tự, nhưng dữ liệu ĐÃ ĐĂNG được hoặc không khớp với dữ liệu hiện có. Nếu nó khớp, tôi lấy id cho dữ liệu đó, sau đó chuyển id đó vào tập lệnh thông qua biến GET trong chuyển hướng. Tôi cũng lưu dữ liệu ĐĂNG trong SESSION. Bây giờ, trang được chuyển hướng sẽ tải dữ liệu được tham chiếu bởi idGET và cũng có quyền truy cập vào dữ liệu khác được gửi bởi POST.
Buttle Butkus

Câu trả lời:


57

Nếu bạn gặp phải vấn đề như vậy, có một chút khả năng là bạn có thể cần phải sửa đổi thiết kế của mình.

Đây là một hạn chế của HTTP mà dữ liệu POST không thể đi cùng với chuyển hướng.

Bạn có thể mô tả những gì bạn đang cố gắng hoàn thành và có thể sau đó chúng ta có thể nghĩ về một số giải pháp gọn gàng.

Nếu bạn không muốn sử dụng các phiên như Matthew đã đề xuất, bạn có thể chuyển các tham số POST trong GET sang trang mới (xem xét một số hạn chế như bảo mật và độ dài tối đa của tham số GET trong chuỗi truy vấn).

CẬP NHẬT bản cập nhật của bạn :) Nghe có vẻ lạ đối với tôi khi bạn có 2 ứng dụng web và những ứng dụng đó sử dụng một views.py (tôi nói đúng chứ?). Dù sao, hãy xem xét việc chuyển dữ liệu của bạn từ POST trong GET sang chế độ xem thích hợp (tất nhiên là trong trường hợp dữ liệu không nhạy cảm).


2
Tôi có thể thấy những gì anh ấy đang cố gắng làm có thể hợp lệ nếu anh ấy đang cố gắng xử lý thông tin đăng nhập đã hết hạn buộc người dùng phải đăng nhập sau khi gửi biểu mẫu ... trong trường hợp đó, anh ấy sẽ muốn giữ lại dữ liệu đã được gửi và không buộc người dùng phải nhập lại mọi thứ sau khi họ hoàn thành màn hình đăng nhập.
Matthew J Morrison

Không chắc liệu tôi có hiểu đúng không nhưng trong trường hợp này, thao tác đăng nhập có thể được thực hiện bằng cách xem đầu tiên với ít sửa đổi mã và không thực hiện các chuyển hướng không cần thiết. Thật tuyệt khi đọc mã exisitng để đưa ra lời khuyên chính xác hơn.
dzida

Tôi đang nói nếu bạn gửi một biểu mẫu và chưa đăng nhập, bạn sẽ được chuyển hướng đến một biểu mẫu đăng nhập ... trong trường hợp đó, bạn sẽ mất bất cứ thứ gì mà bạn đã gửi. Tôi đồng ý về việc có thể xem một số mã hiện có.
Matthew J Morrison

1
Nó không phụ thuộc vào bạn quyết định xem trường hợp sử dụng có hợp lệ hay không, tôi đang phải đối mặt với tình huống tương tự mà chuyển hướng với POST mới là giải pháp hoàn hảo về tính đơn giản và mô đun.
Rabih Kodeih 18/10/12

54

Tôi nghĩ cách tôi có thể sẽ xử lý tình huống này là lưu dữ liệu bài đăng trong phiên, sau đó xóa nó khi tôi không cần nữa. Bằng cách đó, tôi có thể truy cập dữ liệu bài đăng gốc sau khi chuyển hướng mặc dù bài đăng đó đã biến mất.

Điều đó có hiệu quả với những gì bạn đang cố gắng làm không?

Đây là một mẫu mã về những gì tôi đang đề xuất: (hãy nhớ rằng đây là mã chưa được kiểm tra)

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

Một điều khác cần lưu ý ... nếu bạn đang làm điều này và cũng đang tải tệp lên, tôi sẽ không làm theo cách này.


1
Tôi chưa bao giờ sử dụng các phiên, nhưng tôi sẽ xem qua, cảm ơn.
FunLovinCoder

1
đây không phải là phương pháp hay nhất, nhưng vẫn hữu ích. Tôi đoán đối với vấn đề này, chúng tôi sẽ không nhận được bất cứ điều gì đẹp hơn.
Guilherme David da Costa

@GuilhermeDaviddaCosta tại sao bạn nói đó không phải là phương pháp hay nhất? Bạn có thể cho chúng tôi một gợi ý?
Buttle Butkus

bởi vì lưu trữ quá nhiều dữ liệu trong phiên dường như không phải là một ý kiến ​​hay. Nhưng như tôi đã nói, tôi không thể nghĩ ra điều gì đẹp hơn.
Guilherme David da Costa

4
Vâng, điều đó phụ thuộc vào nơi bạn đang lưu trữ phiên của mình. Gần đây, tôi đã thấy mọi người sử dụng toàn bộ máy chủ với memcached cho các phiên và cân bằng tải (sử dụng round robin) mọi yêu cầu. Tôi không muốn đưa ra lời khuyên cho bạn, tôi không thể ủng hộ, nhưng tôi sẽ lưu tệp dưới dạng tạm thời và chỉ nhận được một liên kết cho nó trong phiên. Có vẻ như không ai dùng hết ram trong những ngày này.
Guilherme David da Costa

23

Bạn cần sử dụng Chuyển hướng tạm thời HTTP 1.1 (307).

Thật không may, Django redirect()HTTPResponseRedirect (vĩnh viễn) chỉ trả về 301 hoặc 302. Bạn phải tự triển khai:

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)

Xem thêm mô-đun django.http .

Biên tập:

trên các phiên bản Django gần đây, hãy thay đổi iri_to_urinhập thành:

from django.utils.encoding import iri_to_uri

Các phiên bản mới hơn của Django có chuyển hướng vĩnh viễn HttpResponsePermanentRedirect nhưng không chắc liệu nó có giải quyết được sự cố ban đầu docs.djangoproject.com/en/dev/ref/request-response/…
JiminyCricket

9

sử dụng requestsgói. Nó rất dễ thực hiện

pip install requests

thì bạn có thể gọi bất kỳ url nào bằng bất kỳ phương thức nào và chuyển dữ liệu

trong chế độ xem của bạn yêu cầu nhập

import requests

để đăng dữ liệu, hãy làm theo định dạng

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

để lấy url tuyệt đối trong chế độ xem django, hãy sử dụng

request.build_absolute_uri(reverse('view_name'))

Do đó, mã chế độ xem django trông giống như

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

nơi rlà đối tượng phản ứng với status_codecontentthuộc tính. r.status_codecung cấp mã trạng thái (khi thành công, nó sẽ là 200) và r.contentcung cấp cho nội dung phản hồi. Có một phương thức json ( r.json()) sẽ chuyển đổi phản hồi sang định dạng json

yêu cầu

request.post


4

Chỉ cần gọi chế độ xem mới của bạn từ chế độ xem cũ bằng cách sử dụng cùng một đối tượng yêu cầu. Tất nhiên nó sẽ không dẫn đến chuyển hướng như vậy, nhưng nếu tất cả những gì bạn quan tâm là 'chuyển' dữ liệu từ chế độ xem này sang chế độ xem khác, thì nó sẽ hoạt động.
Tôi đã thử nghiệm đoạn mã sau và nó hoạt động.

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

Bạn có thể sử dụng kết xuấtngữ cảnh với nó:

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

Bạn có thể nhận các vars trong mẫu:

{% If var name %}
 {{ var name }}
{% endif %}

1

Tôi đã phải đối mặt với một vấn đề tương tự gần đây.

Về cơ bản, tôi đã có một biểu mẫu A, khi gửi nó một biểu mẫu B khác sẽ hiển thị, trong đó có một số kết quả + một biểu mẫu. Khi gửi B, tôi muốn hiển thị một số cảnh báo cho người dùng và chỉ giữ người dùng trên B.

Cách tôi giải quyết vấn đề này là hiển thị kết quả trong một <output>trường, trong B.

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

Và tôi đã sử dụng cùng một khung nhìn cho A-> B và B-> B. Bây giờ tôi chỉ cần phân biệt nếu yêu cầu đến từ A hay B và hiển thị cho phù hợp.

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

Nhưng điều này chỉ hoạt động nếu dạng B nhỏ và không động như vậy.


0

Nếu bạn đang sử dụng chuyển hướng sau khi xử lý POST tới AppB, bạn thực sự có thể thoát khỏi việc gọi AppBphương thức từ AppAphương thức.

Một ví dụ:

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

Điều này sẽ mang lại trải nghiệm minh bạch cho người dùng cuối và khách hàng đã thuê bạn có thể sẽ không bao giờ biết sự khác biệt.

Nếu bạn không chuyển hướng sau khi ĐĂNG, bạn có lo lắng về dữ liệu trùng lặp do người dùng làm mới trang không?


Sẽ thật tuyệt nếu một giải pháp đơn giản như thế này hoạt động. Tuy nhiên, tôi cần hiển thị kết quả chi tiết sau khi xử lý dữ liệu. Điều này sẽ yêu cầu các phiên họp (như Matthew J Morrison đề xuất) phải không?
FunLovinCoder

1
Bạn có thể thực hiện theo một trong ba cách. # 1, lưu trữ dữ liệu trong cơ sở dữ liệu và chuyển pkmục nhập mới khi bạn chuyển hướng. # 2, lưu trữ dữ liệu trong chương trình cachephụ trợ và chuyển lại khóa. # 3, lưu trữ nó trong phiên. Bất kỳ điều nào trong số này là hoàn toàn bình thường đối với một ứng dụng web, ngay cả khi nó chỉ là tạm thời. Nếu dữ liệu biểu mẫu không nhỏ để phân tích cú pháp, nó cũng sẽ làm cho hệ thống nhanh hơn nếu đầu ra đã được lưu trong bộ nhớ cache.
Jack M.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.