要将 Turbolinks 5 与 Django 一起使用,如何在使用 redirect() 时自动包含 Turbolinks-Location header?

To use Turbolinks 5 with Django, how can I automate inclusion of the Turbolinks-Location header when using redirect()?

根据 "Following Redirects" (https://github.com/turbolinks/turbolinks#following-redirects) 的 Turbolinks 5 文档:

When you visit location /one and the server redirects you to location /two, you expect the browser’s address bar to display the redirected URL.

However, Turbolinks makes requests using XMLHttpRequest, which transparently follows redirects. There’s no way for Turbolinks to tell whether a request resulted in a redirect without additional cooperation from the server.

解决方法是:

send the Turbolinks-Location header in response to a visit that was redirected, and Turbolinks will replace the browser’s topmost history entry with the value you provide.

The Turbolinks Rails engine performs this optimization automatically for non-GET XHR requests that redirect with the redirect_to helper.

我对在我的 Django (1.11) 项目中使用 Turbolinks 非常感兴趣,我想知道是否有人可以为我指出正确的方向,告诉我如何创建新的 Django redirect() 函数或修改现有函数始终包含重定向功能所需的 Turbolinks-Location header。我绝对不想每次进行重定向时都手动设置此 header。

'Redirecting After a Form Submission' 部分中有一个类似的条目 (https://github.com/turbolinks/turbolinks#redirecting-after-a-form-submission) 如果您能帮助我理解如何实施,我将不胜感激:

If form submission results in a state change on the server that affects cached pages, consider clearing Turbolinks’ cache with Turbolinks.clearCache().

The Turbolinks Rails engine performs this optimization automatically for non-GET XHR requests that redirect with the redirect_to helper.

我确实看到 github 上有一个 "Drop-in turbolinks implementation for Django" 包,但这是从 turbolinks-classic 分叉出来的,源代码没有提到 Turbolinks-Location header所以我确定这不是我要找的。

您提到的 django 包实现了一个 middleware,负责添加 headers。似乎对于旧的 turbolinks,headers 有不同的名称。您可以编写自己的中间件来支持 turbolinks 5。

Instead of submitting forms normally, submit them with XHR.

您可以使用普通的 django 实现此目的。阅读 django CSRF doc - 他们详细解释了必要的内容。

一位 reddit 用户指向该项目 https://github.com/viewflow/django-material/blob/v2/material/middleware.py 中的一段代码后,我确实发现了如何完全按照我的尝试去做。

我将 TurbolinksMiddleware class 复制到我自己的 middleware.py 应用程序目录下,并将其列在我的 settings.py 中

# MIDDLEWARE CONFIGURATION
# --------------------------------------------------------------------------
MIDDLEWARE = [
    .
    .
    .
    'apps.middleware.TurbolinksMiddleware',
]

通过在我的 html 模板中包含 turbolinks.js 的常规安装步骤,一切似乎都正常工作。

这是 TurbolinksMiddleware class,以防它在上面的 link 中不可用:

class TurbolinksMiddleware(object):
    """
    Send the `Turbolinks-Location` header in response to a visit that was redirected,
    and Turbolinks will replace the browser’s topmost history entry .
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)

        is_turbolinks = request.META.get('HTTP_TURBOLINKS_REFERRER')
        is_response_redirect = response.has_header('Location')

        if is_turbolinks:
            if is_response_redirect:
                location = response['Location']
                prev_location = request.session.pop('_turbolinks_redirect_to', None)
                if prev_location is not None:
                    # relative subsequent redirect
                    if location.startswith('.'):
                        location = prev_location.split('?')[0] + location
                request.session['_turbolinks_redirect_to'] = location
            else:
                if request.session.get('_turbolinks_redirect_to'):
                    location = request.session.pop('_turbolinks_redirect_to')
                    response['Turbolinks-Location'] = location
        return response