如何实现“后退” Django 模板上的链接?

发布于 2024-07-13 06:57:34 字数 245 浏览 4 评论 0原文

我正在使用 Django 进行工具处理,我想知道是否有一种简单的方法来创建“后退”使用模板系统链接到上一页。

我认为在最坏的情况下,我可以从视图函数中的请求对象获取此信息,并将其传递给模板渲染方法,但我希望我能以某种方式避免所有这些样板代码。

我检查了 Django 模板文档,但没有看到任何明确提到这一点的内容。

I'm tooling around with Django and I'm wondering if there is a simple way to create a "back" link to the previous page using the template system.

I figure that in the worst case I can get this information from the request object in the view function, and pass it along to the template rendering method, but I'm hoping I can avoid all this boilerplate code somehow.

I've checked the Django template docs and I haven't seen anything that mentions this explicitly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

云雾 2024-07-20 06:57:34

实际上它是go(-1)

<input type=button value="Previous Page" onClick="javascript:history.go(-1);">

Actually it's go(-1).

<input type=button value="Previous Page" onClick="javascript:history.go(-1);">
荒人说梦 2024-07-20 06:57:34

这个解决方案对我来说很有效:

<a href="{{request.META.HTTP_REFERER}}">Go back</a>

但之前需要将 'django.core.context_processors.request', 添加到项目设置中的 TEMPLATE_CONTEXT_PROCESSORS 中。

This solution worked out for me:

<a href="{{request.META.HTTP_REFERER}}">Go back</a>

But that's previously adding 'django.core.context_processors.request', to TEMPLATE_CONTEXT_PROCESSORS in your project's settings.

弱骨蛰伏 2024-07-20 06:57:34
<a href="{{request.META.HTTP_REFERER|escape}}">Back</a>

这里|escape用于跳出" "字符串。

<a href="{{request.META.HTTP_REFERER|escape}}">Back</a>

Here |escape is used to get out of the " "string.

萌逼全场 2024-07-20 06:57:34

好吧,您可以

'django.core.context_processors.request',

在您的 settings.TEMPLATE_CONTEXT_PROCESSORS 块中启用:并挂钩引荐来源网址,但这有点令人恶心,并且可能会破坏整个地方。

大多数你想要这个的地方(例如SO上的编辑帖子页面)你都有一个可以挂载的真实对象(在这个例子中,帖子),这样你就可以轻松地找出正确的上一页应该是什么。

Well you can enable:

'django.core.context_processors.request',

in your settings.TEMPLATE_CONTEXT_PROCESSORS block and hook out the referrer but that's a bit nauseating and could break all over the place.

Most places where you'd want this (eg the edit post page on SO) you have a real object to hook on to (in that example, the post) so you can easily work out what the proper previous page should be.

北陌 2024-07-20 06:57:34

您始终可以使用非常简单的客户端选项:

<a href="javascript:history.go(1)">Back</a>

You can always use the client side option which is very simple:

<a href="javascript:history.go(1)">Back</a>
马蹄踏│碎落叶 2024-07-20 06:57:34

对于 RESTful 链接,“后退”通常意味着更高一级:

<a href="../"><input type="button" value="Back" class="btn btn-primary" /></a>

For RESTful links where "Back" usually means going one level higher:

<a href="../"><input type="button" value="Back" class="btn btn-primary" /></a>
断桥再见 2024-07-20 06:57:34

这里提到的所有 Javascript 解决方案以及 request.META.HTTP_REFERER 解决方案有时都可以工作,但两者都会在同一场景(也许还有其他场景)中出现问题。

我通常在创建或更改对象的表单下有一个取消按钮。 如果用户提交表单一次并且服务器端验证失败,则会再次向用户提供包含错误数据的表单。 你猜怎么着,request.META.HTTP_REFERER 现在指向显示表单的 URL。 您可以按“取消”一千次,并且永远不会回到最初编辑/创建链接所在的位置。

我能想到的唯一可靠的解决方案有点复杂,但对我有用。 如果有人知道更简单的解决方案,我很高兴听到它。 :-)
“技巧”是将初始的 HTTP_REFERER 传递到表单中并从那里使用它。 因此,当表单被发布时,它会传递正确的初始引用者。

我是这样做的:

我为完成大部分工作的表单创建了一个 mixin 类:

from django import forms
from django.utils.http import url_has_allowed_host_and_scheme

class FormCancelLinkMixin(forms.Form):
    """ Mixin class that provides a proper Cancel button link. """
    cancel_link = forms.fields.CharField(widget=forms.HiddenInput())

    def __init__(self, *args, **kwargs):
        """
        Override to pop 'request' from kwargs.
        """
        self.request = kwargs.pop("request")
        initial = kwargs.pop("initial", {})
        # set initial value of 'cancel_link' to the referer
        initial["cancel_link"] = self.request.META.get("HTTP_REFERER", "")
        kwargs["initial"] = initial
        super().__init__(*args, **kwargs)

    def get_cancel_link(self):
        """
        Return correct URL for cancelling the form.

        If the form has been submitted, the HTTP_REFERER in request.meta points to
        the view that handles the form, not the view the user initially came from.
        In this case, we use the value of the 'cancel_link' field.

        Returns:
            A safe URL to go back to, should the user cancel the form.

        """
        if self.is_bound:
            url = self.cleaned_data["cancel_link"]
            # prevent open redirects
            if url_has_allowed_host_and_scheme(url, self.request.get_host()):
                return url

        # fallback to current referer, then root URL
        return self.request.META.get("HTTP_REFERER", "/")

用于编辑/创建对象的表单(通常是 ModelForm 子类)可能如下所示:

class SomeModelForm(FormCancelLinkMixin, forms.ModelForm):
    """ Form for creating some model instance. """

    class Meta:
        model = ModelClass
    # ...

视图必须传递当前请求到表格。 对于基于类的视图,您可以重写 get_form_kwargs()

class SomeModelCreateView(CreateView):
    model = SomeModelClass
    form_class = SomeModelForm

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["request"] = self.request
        return kwargs

在显示表单的模板中:

<form method="post">
  {% csrf token %}
  {{ form }}
  <input type="submit" value="Save">
  <a href="{{ form.get_cancel_link }}">Cancel</a>
</form>

All Javascript solutions mentioned here as well as the request.META.HTTP_REFERER solution sometimes work, but both break in the same scenario (and maybe others, too).

I usually have a Cancel button under a form that creates or changes an object. If the user submits the form once and server side validation fails, the user is presented the form again, containing the wrong data. Guess what, request.META.HTTP_REFERER now points to the URL that displays the form. You can press Cancel a thousand times and will never get back to where the initial edit/create link was.

The only solid solution I can think of is a bit involved, but works for me. If someone knows of a simpler solution, I'd be happy to hear from it. :-)
The 'trick' is to pass the initial HTTP_REFERER into the form and use it from there. So when the form gets POSTed to, it passes the correct, initial referer along.

Here is how I do it:

I created a mixin class for forms that does most of the work:

from django import forms
from django.utils.http import url_has_allowed_host_and_scheme

class FormCancelLinkMixin(forms.Form):
    """ Mixin class that provides a proper Cancel button link. """
    cancel_link = forms.fields.CharField(widget=forms.HiddenInput())

    def __init__(self, *args, **kwargs):
        """
        Override to pop 'request' from kwargs.
        """
        self.request = kwargs.pop("request")
        initial = kwargs.pop("initial", {})
        # set initial value of 'cancel_link' to the referer
        initial["cancel_link"] = self.request.META.get("HTTP_REFERER", "")
        kwargs["initial"] = initial
        super().__init__(*args, **kwargs)

    def get_cancel_link(self):
        """
        Return correct URL for cancelling the form.

        If the form has been submitted, the HTTP_REFERER in request.meta points to
        the view that handles the form, not the view the user initially came from.
        In this case, we use the value of the 'cancel_link' field.

        Returns:
            A safe URL to go back to, should the user cancel the form.

        """
        if self.is_bound:
            url = self.cleaned_data["cancel_link"]
            # prevent open redirects
            if url_has_allowed_host_and_scheme(url, self.request.get_host()):
                return url

        # fallback to current referer, then root URL
        return self.request.META.get("HTTP_REFERER", "/")

The form that is used to edit/create the object (usually a ModelForm subclass) might look like this:

class SomeModelForm(FormCancelLinkMixin, forms.ModelForm):
    """ Form for creating some model instance. """

    class Meta:
        model = ModelClass
    # ...

The view must pass the current request to the form. For class based views, you can override get_form_kwargs():

class SomeModelCreateView(CreateView):
    model = SomeModelClass
    form_class = SomeModelForm

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["request"] = self.request
        return kwargs

In the template that displays the form:

<form method="post">
  {% csrf token %}
  {{ form }}
  <input type="submit" value="Save">
  <a href="{{ form.get_cancel_link }}">Cancel</a>
</form>
狼性发作 2024-07-20 06:57:34

对于 Django 管理员更改表单中的“后退”按钮,我最终要做的是自定义模板过滤器来解析和解码模板中的“preserved_filters”变量。 我将以下内容放在自定义 templates/admin/submit_line.html 文件中:

<a href="../{% if original}../{% endif %}?{{ preserved_filters | decode_filter }}">
    {% trans "Back" %}
</a>

然后创建自定义模板过滤器:

from urllib.parse import unquote
from django import template

def decode_filter(variable):
    if variable.startswith('_changelist_filters='):
        return unquote(variable[20:])
    return variable

register = template.Library()
register.filter('decode_filter', decode_filter)

For a 'back' button in change forms for Django admin what I end up doing is a custom template filter to parse and decode the 'preserved_filters' variable in the template. I placed the following on a customized templates/admin/submit_line.html file:

<a href="../{% if original}../{% endif %}?{{ preserved_filters | decode_filter }}">
    {% trans "Back" %}
</a>

And then created a custom template filter:

from urllib.parse import unquote
from django import template

def decode_filter(variable):
    if variable.startswith('_changelist_filters='):
        return unquote(variable[20:])
    return variable

register = template.Library()
register.filter('decode_filter', decode_filter)
樱娆 2024-07-20 06:57:34

使用客户端解决方案将是正确的解决方案。

<a href="javascript:history.go(-1)" class="btn btn-default">Cancel</a>

Using client side solution would be the proper solution.

<a href="javascript:history.go(-1)" class="btn btn-default">Cancel</a>
满地尘埃落定 2024-07-20 06:57:34

在 Web 开发中,有多种方法来实现后退按钮。 我想分享两种常见的方法。

  1. 将 JavaScript 与 onclick 结合使用:
<button onclick="history.back()">Back</button>

此方法利用 JavaScript 的 History.back() 函数导航到浏览器历史记录中的上一页。 这是一个简单而有效的解决方案。

  1. 像上面的其他评论一样使用 HTTP_REFERER :
<a href="{{request.META.HTTP_REFERER}}">Back</a>

所有这些方法都会存储页面的历史记录,因此,如果您打开没有历史记录的页面并尝试返回,它将不起作用,只需重新加载页面即可。 这项工作按预期进行。

In web development, there are various methods to implement a back button. I'd like to share two common approaches.

  1. Using JavaScript with onclick:
<button onclick="history.back()">Back</button>

This method utilizes JavaScript's history.back() function to navigate to the previous page in the browser history. It's a straightforward and effective solution.

  1. Using HTTP_REFERER like other comments above:
<a href="{{request.META.HTTP_REFERER}}">Back</a>

All this ways make store an history of pages, so if you open the page without historic and try back it don't will work, just reload the page. This work as intend.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文