django重定向
When you build a Python web application with the Django framework, you’ll at some point have to redirect the user from one URL to another.
当使用Django框架构建Python Web应用程序时,您将不得不将用户从一个URL重定向到另一个URL。
In this guide, you’ll learn everything you need to know about HTTP redirects and how to deal with them in Django. At the end of this tutorial, you’ll:
在本指南中,您将学习有关HTTP重定向以及如何在Django中进行处理所需的所有知识。 在本教程的最后,您将:
This tutorial assumes that you’re familiar with the basic building blocks of a Django application, like views and URL patterns.
本教程假定您熟悉Django应用程序的基本构建块,例如view和URL pattern 。
In Django, you redirect the user to another URL by returning an instance of HttpResponseRedirect
or HttpResponsePermanentRedirect
from your view. The simplest way to do this is to use the function redirect()
from the module django.shortcuts
. Here’s an example:
在Django中,您可以通过从视图返回HttpResponseRedirect
或HttpResponsePermanentRedirect
实例来将用户重定向到另一个URL。 最简单的方法是使用django.shortcuts
模块中的redirect()
函数。 这是一个例子:
# views.py
# views.py
from from django.shortcuts django.shortcuts import import redirect
redirect
def def redirect_viewredirect_view (( requestrequest ):
):
response response = = redirectredirect (( '/redirect-success/''/redirect-success/' )
)
return return response
response
Just call redirect()
with a URL in your view. It will return a HttpResponseRedirect
class, which you then return from your view.
只需在视图中调用带有URL的redirect()
。 它将返回HttpResponseRedirect
类,然后从视图中返回该类。
A view returning a redirect has to be added to your urls.py
, like any other view:
与其他视图一样,必须将返回重定向的视图添加到urls.py
:
Assuming this is the main urls.py
of your Django project, the URL /redirect/
now redirects to /redirect-success/
.
假设这是Django项目的主要urls.py
,URL /redirect/
现在重定向到/redirect-success/
。
To avoid hard-coding the URL, you can call redirect()
with the name of a view or URL pattern or a model to avoid hard-coding the redirect URL. You can also create a permanent redirect by passing the keyword argument permanent=True
.
为避免对URL进行硬编码,可以使用视图或URL模式或模型的名称调用redirect()
来避免对重定向URL进行硬编码。 您还可以通过传递关键字参数permanent=True
来创建永久重定向。
This article could end here, but then it could hardly be called “The Ultimate Guide to Django Redirects.” We will take a closer look at the redirect()
function in a minute and also get into the nitty-gritty details of HTTP status codes and different HttpRedirectResponse
classes, but let’s take a step back and start with a fundamental question.
本文可能到此结束,但之后很难称为“ Django重定向的终极指南”。 我们将在一分钟内仔细研究redirect()
函数,并深入了解HTTP状态代码和不同的HttpRedirectResponse
类的细节,但让我们退后一步,从一个基本问题开始。
You might wonder why you’d ever want to redirect a user to a different URL in the first place. To get an idea where redirects make sense, have a look at how Django itself incorporates redirects into features that the framework provides by default:
您可能想知道为什么首先要将用户重定向到其他URL。 要了解重定向在哪里有意义,请查看Django本身如何将重定向合并到框架默认提供的功能中:
What would an alternative implementation without redirects look like? If a user has to log in to view a page, you could simply display a page that says something like “Click here to log in.” This would work, but it would be inconvenient for the user.
没有重定向的替代实现是什么样的? 如果用户必须登录才能查看页面,则只需显示一个页面,上面写着“单击此处登录”。 这将起作用,但是对于用户而言将是不便的。
URL shorteners like http://bit.ly are another example of where redirects come in handy: you type a short URL into the address bar of your browser and are then redirected to a page with a long, unwieldy URL.
像http://bit.ly这样的URL缩短器是重定向很方便的另一个示例:您在浏览器的地址栏中输入一个简短的URL,然后重定向到带有冗长的URL的页面。
In other cases, redirects are not just a matter of convenience. Redirects are an essential instrument to guide the user through a web application. After performing some kind of operation with side effects, like creating or deleting an object, it’s a best practice to redirect to another URL to prevent accidentally performing the operation twice.
在其他情况下,重定向不只是为了方便。 重定向是引导用户浏览Web应用程序的重要工具。 在执行了一些具有副作用的操作(例如创建或删除对象)之后,最佳做法是重定向到另一个URL,以防止两次意外执行该操作。
One example of this use of redirects is form handling, where a user is redirected to another URL after successfully submitting a form. Here’s a code sample that illustrates how you’d typically handle a form:
这种使用重定向的示例是表单处理,其中,用户在成功提交表单后将重定向到另一个URL。 这是一个代码示例,说明您通常如何处理表单:
from from django django import import forms
forms
from from django.http django.http import import HttpResponseRedirect
HttpResponseRedirect
from from django.shortcuts django.shortcuts import import redirectredirect , , render
render
def def send_messagesend_message (( namename , , messagemessage ):
):
# Code for actually sending the message goes here
# Code for actually sending the message goes here
class class ContactFormContactForm (( formsforms .. FormForm ):
):
name name = = formsforms .. CharFieldCharField ()
()
message message = = formsforms .. CharFieldCharField (( widgetwidget == formsforms .. TextareaTextarea )
)
def def contact_viewcontact_view (( requestrequest ):
):
# The request method 'POST' indicates
# The request method 'POST' indicates
# that the form was submitted
# that the form was submitted
if if requestrequest .. method method == == 'POST''POST' : : # 1
# 1
# Create a form instance with the submitted data
# Create a form instance with the submitted data
form form = = ContactFormContactForm (( requestrequest .. POSTPOST ) ) # 2
# 2
# Validate the form
# Validate the form
if if formform .. is_validis_valid (): (): # 3
# 3
# If the form is valid, perform some kind of
# If the form is valid, perform some kind of
# operation, for example sending a message
# operation, for example sending a message
send_messagesend_message (
(
formform .. cleaned_datacleaned_data [[ 'name''name' ],
],
formform .. cleaned_datacleaned_data [[ 'message''message' ]
]
)
)
# After the operation was successful,
# After the operation was successful,
# redirect to some other page
# redirect to some other page
return return redirectredirect (( '/success/''/success/' ) ) # 4
# 4
elseelse : : # 5
# 5
# Create an empty form instance
# Create an empty form instance
form form = = ContactFormContactForm ()
()
return return renderrender (( requestrequest , , 'contact_form.html''contact_form.html' , , {{ 'form''form' : : formform })
})
The purpose of this view is to display and handle a contact form that allows the user to send a message. Let’s follow it step by step:
该视图的目的是显示和处理允许用户发送消息的联系表单。 让我们逐步进行操作:
First the view looks at the request method. When the user visits the URL connected to this view, the browser performs a GET
request.
If the view is called with a POST
request, the POST
data is used to instantiate a ContactForm
object.
If the form is valid, the form data is passed to send_message()
. This function is not relevant in this context and therefore not shown here.
After sending the message, the view returns a redirect to the URL /success/
. This is the step we are interested in. For simplicity, the URL is hard-coded here. You’ll see later how you can avoid that.
If the view receives a GET
request (or, to be precise, any kind of request that is not a POST
request), it creates an instance of ContactForm
and uses django.shortcuts.render()
to render the contact_form.html
template.
首先,视图查看请求方法。 当用户访问连接到此视图的URL时,浏览器将执行GET
请求。
如果使用POST
请求调用该视图,则POST
数据用于实例化ContactForm
对象。
如果表单有效,则将表单数据传递给send_message()
。 此功能在此上下文中不相关,因此此处未显示。
发送消息后,视图将重定向到URL /success/
。 这是我们感兴趣的步骤。为简单起见,URL在此处进行了硬编码。 稍后您将看到如何避免这种情况。
如果视图接收到GET
请求(或更确切地说,是不是POST
请求的任何类型的请求),它将创建ContactForm
实例,并使用django.shortcuts.render()
呈现contact_form.html
模板。
If the user now hits reload, only the /success/
URL is reloaded. Without the redirect, reloading the page would re-submit the form and send another message.
如果用户现在点击重新加载,则仅重新加载/success/
URL。 如果没有重定向,重新加载页面将重新提交表单并发送另一条消息。
Now you know why redirects make sense, but how do they work? Let’s have a quick recap of what happens when you enter a URL in the address bar of your web browser.
现在您知道了为什么重定向有意义,但是它们如何工作? 让我们快速回顾一下在Web浏览器的地址栏中输入URL时发生的情况。
Let’s assume you’ve created a Django application with a “Hello World” view that handles the path /hello/
. You are running your application with the Django development server, so the complete URL is http://127.0.0.1:8000/hello/
.
假设您已经创建了带有处理路径/hello/
的“ Hello World”视图的Django应用程序。 您正在使用Django开发服务器运行应用程序,因此完整的URL为http://127.0.0.1:8000/hello/
。
When you enter that URL in your browser, it connects to port 8000
on the server with the IP address 127.0.0.1
and sends an HTTP GET
request for the path /hello/
. The server replies with an HTTP response.
当您在浏览器中输入该URL时,它将连接到IP地址为127.0.0.1
的服务器上的端口8000
,并为路径/hello/
发送HTTP GET
请求。 服务器以HTTP响应进行回复。
HTTP is text-based, so it’s relatively easy to look at the back and forth between the client and the server. You can use the command line tool curl
with the option --include
to have a look at the complete HTTP response including the headers, like this:
HTTP是基于文本的,因此查看客户端和服务器之间的来回相对容易。 您可以使用带有--include
选项的命令行工具curl
来查看完整的HTTP响应,包括标头,如下所示:
As you can see, an HTTP response starts with a status line that contains a status code and a status message. The status line is followed by an arbitrary number of HTTP headers. An empty line indicates the end of the headers and the start of the response body, which contains the actual data the server wants to send.
如您所见,HTTP响应以包含状态码和状态消息的状态行开始。 状态行后跟任意数量的HTTP标头。 空行指示标头的末尾和响应正文的开始,其中包含服务器要发送的实际数据。
What does a redirect response look like? Let’s assume the path /redirect/
is handled by redirect_view()
, shown earlier. If you access http://127.0.0.1:8000/redirect/
with curl
, your console looks like this:
重定向响应是什么样的? 假设路径/redirect/
由前面显示的redirect_view()
处理。 如果使用curl
访问http://127.0.0.1:8000/redirect/
,则您的控制台如下所示:
$ curl --include http://127.0.0.1:8000/redirect/
$ curl --include http://127.0.0.1:8000/redirect/
HTTP/1.1 302 Found
HTTP/1.1 302 Found
Date: Sun, 01 Jul 2018 20:35:34 GMT
Date: Sun, 01 Jul 2018 20:35:34 GMT
Server: WSGIServer/0.2 CPython/3.6.3
Server: WSGIServer/0.2 CPython/3.6.3
Content-Type: text/html; charset=utf-8
Content-Type: text/html; charset=utf-8
Location: /redirect-success/
Location: /redirect-success/
X-Frame-Options: SAMEORIGIN
X-Frame-Options: SAMEORIGIN
Content-Length: 0
Content-Length: 0
The two responses might look similar, but there are some key differences. The redirect:
这两个响应可能看起来相似,但是存在一些关键差异。 重定向:
302
versus 200
)Location
header with a relative URL302
和200
) Location
标头 The primary differentiator is the status code. The specification of the HTTP standard says the following:
主要区别在于状态码。 HTTP标准的规范说明如下:
The 302 (Found) status code indicates that the target resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client ought to continue to use the effective request URI for future requests. The server SHOULD generate a Location header field in the response containing a URI reference for the different URI. The user agent MAY use the Location field value for automatic redirection. (Source)
302(已找到)状态代码指示目标资源暂时位于其他URI下。 由于重定向有时可能会更改,因此客户端应继续将有效请求URI用于将来的请求。 服务器应该在响应中生成一个Location头字段,其中包含针对不同URI的URI引用。 用户代理可以使用位置字段值进行自动重定向。 ( 来源 )
In other words, whenever the server sends a status code of 302
, it says to the client, “Hey, at the moment, the thing you are looking for can be found at this other location.”
换句话说,每当服务器发送状态代码302
,它对客户端说:“嘿,此刻,您正在寻找的东西可以在另一个位置找到。”
A key phrase in the specification is “MAY use the Location field value for automatic redirection.” It means that you can’t force the client to load another URL. The client can choose to wait for user confirmation or decide not to load the URL at all.
规范中的一个关键词是“请使用位置字段值进行自动重定向”。 这意味着您不能强制客户端加载另一个URL。 客户端可以选择等待用户确认或决定完全不加载URL。
Now you know that a redirect is just an HTTP response with a 3xx
status code and a Location
header. The key takeaway here is that an HTTP redirect is like any old HTTP response, but with an empty body, 3xx status code, and a Location
header.
现在,您知道重定向只是带有3xx
状态代码和Location
标头的HTTP响应。 这里的关键要点是HTTP重定向就像任何旧的HTTP响应一样,但是具有空主体,3xx状态代码和Location
标头。
That’s it. We’ll tie this back into Django momentarily, but first let’s take a look at two types of redirects in that 3xx
status code range and see why they matter when it comes to web development.
而已。 我们暂时将其与Django联系起来,但是首先让我们看一下3xx
状态码范围内的两种重定向类型,并了解在Web开发中它们为何如此重要。
The HTTP standard specifies several redirect status codes, all in the 3xx
range. The two most common status codes are 301 Permanent Redirect
and 302 Found
.
HTTP标准指定了几个重定向状态代码,它们都在3xx
范围内。 两种最常见的状态代码是301 Permanent Redirect
和302 Found
。
A status code 302 Found
indicates a temporary redirect. A temporary redirect says, “At the moment, the thing you’re looking for can be found at this other address.” Think of it like a store sign that reads, “Our store is currently closed for renovation. Please go to our other store around the corner.” As this is only temporary, you’d check the original address the next time you go shopping.
302 Found
的状态码302 Found
指示临时重定向。 临时重定向说:“目前,您要查找的内容可以在其他地址找到。” 可以将其想象为一个商店标语,上面写着:“我们的商店目前已关闭以进行翻新。 请到我们附近的其他商店。” 由于这只是暂时的,因此下次购物时会检查原始地址。
Note: In HTTP 1.0, the message for status code 302 was Temporary Redirect
. The message was changed to Found
in HTTP 1.1.
注意:在HTTP 1.0中,状态代码302的消息是Temporary Redirect
。 该消息已更改为“在HTTP 1.1中Found
。
As the name implies, permanent redirects are supposed to be permanent. A permanent redirect tells the browser, “The thing you’re looking for is no longer at this address. It’s now at this new address, and it will never be at the old address again.”
顾名思义,永久重定向应该是永久的。 永久重定向告诉浏览器:“您要找的东西不再位于此地址。 现在是在这个新地址,再也不会在旧地址了。”
A permanent redirect is like a store sign that reads, “We moved. Our new store is just around the corner.” This change is permanent, so the next time you want to go to the store, you’d go straight to the new address.
永久重定向就像一个商店标语,上面写着“我们搬了。 我们的新店就在附近。” 此更改是永久性的,因此下次您要去商店时,您将直接转到新地址。
Note: Permanent redirects can have unintended consequences. Finish this guide before using a permanent redirect or jump straight to the section “Permanent redirects are permanent.”
注意:永久重定向可能会带来意想不到的后果。 在使用永久重定向之前,请先完成本指南,或直接跳至“永久重定向为永久”部分。
Browsers behave similarly when handling redirects: when a URL returns a permanent redirect response, this response is cached. The next time the browser encounters the old URL, it remembers the redirect and directly requests the new address.
浏览器在处理重定向时的行为类似:URL返回永久重定向响应时,将缓存此响应。 下次浏览器遇到旧URL时,它将记住重定向并直接请求新地址。
Caching a redirect saves an unnecessary request and makes for a better and faster user experience.
缓存重定向可节省不必要的请求,并提供更好,更快的用户体验。
Furthermore, the distinction between temporary and permanent redirects is relevant for Search Engine Optimization.
此外,临时重定向和永久重定向之间的区别与搜索引擎优化有关。
Now you know that a redirect is just an HTTP response with a 3xx
status code and a Location
header.
现在,您知道重定向只是带有3xx
状态代码和Location
标头的HTTP响应。
You could build such a response yourself from a regular HttpResponse
object:
您可以自己从常规HttpResponse
对象构建这样的响应:
This solution is technically correct, but it involves quite a bit of typing.
这个解决方案在技术上是正确的,但是涉及很多输入。
HTTPResponseRedirect
类 (The HTTPResponseRedirect
Class)You can save yourself some typing with the class HttpResponseRedirect
, a subclass of HttpResponse
. Just instantiate the class with the URL you want to redirect to as the first argument, and the class will set the correct status and Location header:
您可以保存自己的一些打字类HttpResponseRedirect
,的一个子类HttpResponse
。 只需使用要重定向到的URL作为第一个参数实例化该类,该类将设置正确的状态和Location标头:
def def redirect_viewredirect_view (( requestrequest ):
):
return return HttpResponseRedirectHttpResponseRedirect (( '/redirect/success/''/redirect/success/' )
)
You can play with the HttpResponseRedirect
class in the Python shell to see what you’re getting:
您可以在Python Shell中使用HttpResponseRedirect
类来查看得到的内容:
There is also a class for permanent redirects, which is aptly named HttpResponsePermanentRedirect
. It works the same as HttpResponseRedirect
, the only difference is that it has a status code of 301 (Moved Permanently)
.
还有一个用于永久重定向的类,恰当地命名为HttpResponsePermanentRedirect
。 它的工作原理与HttpResponseRedirect
相同,唯一的区别是它的状态代码为301 (Moved Permanently)
。
Note: In the examples above, the redirect URLs are hard-coded. Hard-coding URLs is bad practice: if the URL ever changes, you have to search through all your code and change any occurrences. Let’s fix that!
注意:在上面的示例中,重定向URL是硬编码的。 硬编码URL是一种不好的做法:如果URL发生更改,则必须搜索所有代码并更改所有出现的位置。 让我们解决这个问题!
You could use django.urls.reverse()
to build a URL, but there is a more convenient way as you will see in the next section.
您可以使用django.urls.reverse()
来构建URL,但是有一种更方便的方法,如您在下一节中看到的。
redirect()
函数 (The redirect()
Function)To make your life easier, Django provides the versatile shortcut function you’ve already seen in the introduction: django.shortcuts.redirect()
.
为了使您的生活更轻松,Django提供了引言中已经介绍的通用快捷功能: django.shortcuts.redirect()
。
You can call this function with:
您可以通过以下方式调用此函数:
get_absolute_url()
methodget_absolute_url()
方法的模型实例或任何其他对象 It will take the appropriate steps to turn the arguments into a URL and return an HTTPResponseRedirect
. If you pass permanent=True
, it will return an instance of HttpResponsePermanentRedirect
, resulting in a permanent redirect.
它将采取适当的步骤将参数转换为URL并返回HTTPResponseRedirect
。 如果传递permanent=True
,它将返回HttpResponsePermanentRedirect
实例,从而导致永久重定向。
Here are three examples to illustrate the different use cases:
以下是三个示例来说明不同的用例:
Passing a model:
from django.shortcuts import redirect
def model_redirect_view(request):
product = Product.objects.filter(featured=True).first()
return redirect(product)
redirect()
will call product.get_absolute_url()
and use the result as redirect target. If the given class, in this case Product
, doesn’t have a get_absolute_url()
method, this will fail with a TypeError
.
Passing a URL name and arguments:
redirect()
will try to use its given arguments to reverse a URL. This example assumes your URL patterns contain a pattern like this:
path('/product//', 'product_detail_view', name='product_detail')
Passing a URL:
redirect()
will treat any string containing a /
or .
as a URL and use it as redirect target.
传递模型:
from django.shortcuts import redirect
def model_redirect_view ( request ):
product = Product . objects . filter ( featured = True ) . first ()
return redirect ( product )
redirect()
将调用product.get_absolute_url()
并将结果用作重定向目标。 如果给定的类(在本例中为Product
)没有get_absolute_url()
方法,则它将失败,并显示TypeError
。
传递URL名称和参数:
redirect()
将尝试使用其给定的参数来反向URL。 本示例假定您的URL模式包含如下模式:
path('/product//', 'product_detail_view', name='product_detail')
传递网址:
redirect()
将处理任何包含/
或.
作为URL,并将其用作重定向目标。
RedirectView
基于类的视图 (The RedirectView
Class-Based View)If you have a view that does nothing but returning a redirect, you could use the class-based view django.views.generic.base.RedirectView
.
如果您的视图只返回重定向,则可以使用基于类的视图django.views.generic.base.RedirectView
。
You can tailor RedirectView
to your needs through various attributes.
您可以通过各种属性来定制RedirectView
来满足您的需求。
If the class has a .url
attribute, it will be used as a redirect URL. String formatting placeholders are replaced with named arguments from the URL:
如果该类具有.url
属性,它将用作重定向URL。 字符串格式的占位符将替换为URL中的命名参数:
# urls.py
# urls.py
from from django.urls django.urls import import path
path
from from .views .views import import SearchRedirectView
SearchRedirectView
urlpatterns urlpatterns = = [
[
pathpath (( '/search//' '/search//' , , SearchRedirectViewSearchRedirectView .. as_viewas_view ())
())
]
]
# views.py
# views.py
from from django.views.generic.base django.views.generic.base import import RedirectView
RedirectView
class class SearchRedirectViewSearchRedirectView (( RedirectViewRedirectView ):
):
url url = = 'https://google.com/?q='https://google.com/?q= %(term)s%(term)s '
'
The URL pattern defines an argument term
, which is used in SearchRedirectView
to build the redirect URL. The path /search/kittens/
in your application will redirect you to https://google.com/?q=kittens
.
URL模式定义了一个自变量term
,在SearchRedirectView
使用该term
来构建重定向URL。 应用程序中的/search/kittens/
路径会将您重定向到https://google.com/?q=kittens
。
Instead of subclassing RedirectView
to overwrite the url
attribute, you can also pass the keyword argument url
to as_view()
in your urlpatterns
:
除了将RedirectView
子类化以覆盖url
属性之外,您还可以在urlpatterns
关键字参数url
传递给as_view()
:
You can also overwrite get_redirect_url()
to get a completely custom behavior:
您还可以覆盖get_redirect_url()
以获得完全自定义的行为:
from from random random import import choice
choice
from from django.views.generic.base django.views.generic.base import import RedirectView
RedirectView
class class RandomAnimalViewRandomAnimalView (( RedirectViewRedirectView ):
):
animal_urls animal_urls = = [[ '/dog/''/dog/' , , '/cat/''/cat/' , , '/parrot/''/parrot/' ]
]
is_permanent is_permanent = = True
True
def def get_redirect_urlget_redirect_url (( ** argsargs , , **** kwargskwargs ):
):
return return choicechoice (( selfself .. animal_urlsanimal_urls )
)
This class-based view redirects to a URL picked randomly from .animal_urls
.
基于此类的视图重定向到从.animal_urls
随机选择的URL。
django.views.generic.base.RedirectView
offers a few more hooks for customization. Here is the complete list:
django.views.generic.base.RedirectView
提供了更多用于自定义的挂钩。 这是完整的列表:
.url
If this attribute is set, it should be a string with a URL to redirect to. If it contains string formatting placeholders like %(name)s
, they are expanded using the keyword arguments passed to the view.
.pattern_name
If this attribute is set, it should be the name of a URL pattern to redirect to. Any positional and keyword arguments passed to the view are used to reverse the URL pattern.
.permanent
If this attribute is True
, the view returns a permanent redirect. It defaults to False
.
.query_string
If this attribute is True
, the view appends any provided query string to the redirect URL. If it is False
, which is the default, the query string is discarded.
get_redirect_url(*args, **kwargs)
This method is responsible for building the redirect URL. If this method returns None
, the view returns a 410 Gone
status.
The default implementation first checks .url
. It treats .url
as an “old-style” format string, using any named URL parameters passed to the view to expand any named format specifiers.
If .url
is not set, it checks if .pattern_name
is set. If it is, it uses it to reverse a URL with any positional and keyword arguments it received.
You can change that behavior in any way you want by overwriting this method. Just make sure it returns a string containing a URL.
.url
如果设置了此属性,则它应该是带有重定向到的URL的字符串。 如果它包含字符串格式的占位符(如%(name)s
,则使用传递给视图的关键字参数扩展它们。
.pattern_name
如果设置了此属性,则它应该是要重定向到的URL模式的名称。 传递给视图的任何位置和关键字参数都用于反转URL模式。
.permanent
如果此属性为True
,则视图返回永久重定向。 默认为False
。
.query_string
如果此属性为True
,则视图会将任何提供的查询字符串附加到重定向URL。 如果它是False
,这是默认值,则查询字符串将被丢弃。
get_redirect_url(*args, **kwargs)
此方法负责构建重定向URL。 如果此方法返回None
,则视图返回410 Gone
状态。
默认实现首先检查.url
。 它使用传递给视图的任何命名URL参数扩展任何命名格式说明符 ,将.url
视为“旧式” 格式字符串 。
如果未设置.url
,则检查是否设置了.pattern_name
。 如果是的话,它将使用它来反转带有接收到的任何位置和关键字参数的URL。
您可以通过覆盖此方法以任何方式更改此行为。 只要确保它返回包含URL的字符串即可。
Note: Class-based views are a powerful concept but can be a bit difficult to wrap your head around. Unlike regular function-based views, where it’s relatively straightforward to follow the flow of the code, class-based views are made up of a complex hierarchy of mixins and base classes.
注意:基于类的视图是一个强大的概念,但可能难以绕开。 与常规的基于函数的视图不同,后者遵循代码流程相对简单,而基于类的视图则由混合类和基类的复杂层次结构组成。
A great tool to make sense of a class-based view class is the website Classy Class-Based Views.
网站Classy Class-Based Views是了解基于类的视图类的一个很好的工具。
You could implement the functionality of RandomAnimalView
from the example above with this simple function-based view:
您可以使用简单的基于函数的视图从上面的示例中实现RandomAnimalView
的功能:
As you can see, the class-based approach does not provide any obvious benefit while adding some hidden complexity. That raises the question: when should you use RedirectView
?
如您所见,基于类的方法在增加一些隐藏的复杂性的同时并没有提供任何明显的好处。 这就提出了一个问题:什么时候应该使用RedirectView
?
If you want to add a redirect directly in your urls.py
, using RedirectView
makes sense. But if you find yourself overwriting get_redirect_url
, a function-based view might be easier to understand and more flexible for future enhancements.
如果您想直接在urls.py
添加重定向,则使用RedirectView
是有意义的。 但是,如果您发现自己覆盖了get_redirect_url
,则基于函数的视图可能更易于理解,并且对于将来的增强功能更加灵活。
Once you know that you probably want to use django.shortcuts.redirect()
, redirecting to a different URL is quite straight-forward. But there are a couple of advanced use cases that are not so obvious.
一旦知道您可能想使用django.shortcuts.redirect()
,重定向到另一个URL django.shortcuts.redirect()
简单了。 但是,有一些不太明显的高级用例。
Sometimes, you want to pass some parameters to the view you’re redirecting to. Your best option is to pass the data in the query string of your redirect URL, which means redirecting to a URL like this:
有时,您想将一些参数传递给您要重定向到的视图。 最好的选择是在重定向URL的查询字符串中传递数据,这意味着重定向到如下URL:
http://example.com/redirect-path/?parameter=value
http://example.com/redirect-path/?parameter=value
Let’s assume you want to redirect from some_view()
to product_view()
, but pass an optional parameter category
:
假设您要从some_view()
重定向到product_view()
,但传递一个可选的参数category
:
The code in this example is quite dense, so let’s follow it step by step:
此示例中的代码非常密集,因此让我们逐步进行操作:
First, you use django.urls.reverse()
to get the URL mapping to product_view()
.
Next, you have to build the query string. That’s the part after the question mark. It’s advisable to use urllib.urlparse.urlencode()
for that, as it will take care of properly encoding any special characters.
Now you have to join base_url
and query_string
with a question mark. A format string works fine for that.
Finally, you pass url
to django.shortcuts.redirect()
or to a redirect response class.
In product_view()
, your redirect target, the parameter will be available in the request.GET
dictionary. The parameter might be missing, so you should use requests.GET.get('category')
instead of requests.GET['category']
. The former returns None
when the parameter does not exist, while the latter would raise an exception.
首先,使用django.urls.reverse()
获取到product_view()
的URL映射。
接下来,您必须构建查询字符串。 那是问号之后的部分。 建议为此使用urllib.urlparse.urlencode()
,因为它将负责正确编码任何特殊字符。
现在,您必须将base_url
和query_string
加上一个问号。 格式字符串可以正常工作。
最后,将url
传递给django.shortcuts.redirect()
或重定向响应类。
在您的重定向目标product_view()
,该参数将在request.GET
词典中可用。 该参数可能会丢失,因此您应该使用requests.GET.get('category')
而不是requests.GET['category']
。 当参数不存在时,前者返回None
,而后者将引发异常。
Note: Make sure to validate any data you read from query strings. It might seem like this data is under your control because you created the redirect URL.
注意:确保验证从查询字符串读取的所有数据。 由于您创建了重定向URL,因此这些数据似乎在您的控制之下。
In reality, the redirect could be manipulated by the user and must not be trusted, like any other user input. Without proper validation, an attacker might be able gain unauthorized access.
实际上,重定向可以由用户操纵,并且不得像其他任何用户输入一样被信任。 没有适当的验证, 攻击者可能会获得未经授权的访问 。
Django provides HTTP response classes for the status codes 301
and 302
. Those should cover most use cases, but if you ever have to return status codes 303
, 307
, or 308
, you can quite easily create your own response class. Simply subclass HttpResponseRedirectBase
and overwrite the status_code
attribute:
Django为状态码301
和302
提供HTTP响应类。 这些应该覆盖大多数使用情况,但如果你有返回状态代码303
, 307
,或308
,你可以很容易地创建自己的响应等级。 只需将HttpResponseRedirectBase
子类化并覆盖status_code
属性即可:
class class HttpResponseTemporaryRedirectHttpResponseTemporaryRedirect (( HttpResponseRedirectBaseHttpResponseRedirectBase ):
):
status_code status_code = = 307
307
Alternatively, you can use the django.shortcuts.redirect()
method to create a response object and change the return value. This approach makes sense when you have the name of a view or URL or a model you want to redirect to:
另外,您可以使用django.shortcuts.redirect()
方法创建响应对象并更改返回值。 当您具有要重定向到的视图或URL或模型的名称时,此方法很有意义:
Note: There is actually a third class with a status code in the 3xx
range: HttpResponseNotModified
, with the status code 304
. It indicates that the content URL has not changed and that the client can use a cached version.
注意:实际上,存在第三类,其状态码在3xx
范围内: HttpResponseNotModified
,状态码为304
。 它指示内容URL尚未更改,并且客户端可以使用缓存的版本。
One could argue that 304 Not Modified
response redirects to the cached version of a URL, but that’s a bit of a stretch. Consequently, it is no longer listed in the “Redirection 3xx” section of the HTTP standard.
有人可能会说304 Not Modified
响应重定向到URL的缓存版本,但这有点麻烦。 因此,它不再列在HTTP标准的“重定向3xx”部分中。
The simplicity of django.shortcuts.redirect()
can be deceiving. The function itself doesn’t perform a redirect: it just returns a redirect response object. You must return this response object from your view (or in a middleware). Otherwise, no redirect will happen.
django.shortcuts.redirect()
的简单性可以欺骗。 该函数本身不执行重定向:它仅返回重定向响应对象。 您必须从视图(或在中间件中)返回此响应对象。 否则,将不会发生重定向。
But even if you know that just calling redirect()
is not enough, it’s easy to introduce this bug into a working application through a simple refactoring. Here’s an example to illustrate that.
但是,即使您知道仅调用redirect()
还是不够的,也可以通过简单的重构将这个错误引入正在运行的应用程序中,这很容易。 这是一个例子来说明这一点。
Let’s assume you are building a shop and have a view that is responsible for displaying a product. If the product does not exist, you redirect to the homepage:
假设您正在建立一家商店,并且拥有负责展示产品的视图。 如果该产品不存在,请重定向到主页:
def def product_viewproduct_view (( requestrequest , , product_idproduct_id ):
):
trytry :
:
product product = = ProductProduct .. objectsobjects .. getget (( pkpk == product_idproduct_id )
)
except except ProductProduct .. DoesNotExistDoesNotExist :
:
return return redirectredirect (( '/''/' )
)
return return renderrender (( requestrequest , , 'product_detail.html''product_detail.html' , , {{ 'product''product' : : productproduct })
})
Now you want to add a second view to display customer reviews for a product. It should also redirect to the homepage for non-existing products, so as a first step, you extract this functionality from product_view()
into a helper function get_product_or_redirect()
:
现在,您要添加第二个视图以显示产品的客户评论。 它还应该重定向到不存在产品的主页,因此,第一步,请将此功能从product_view()
提取到帮助函数get_product_or_redirect()
:
Unfortunately, after the refactoring, the redirect does not work anymore.
不幸的是,在重构之后,重定向不再起作用。
Can you spot the error? Show/Hide
您能发现错误吗? 显示隐藏
The result of redirect()
is returned from get_product_or_redirect()
, but product_view()
does not return it. Instead, it is passed to the template.
redirect()
的结果是从get_product_or_redirect()
返回的,但product_view()
不会返回它。 而是将其传递到模板。
Depending on how you use the product
variable in the product_detail.html
template, this might not result in an error message and just display empty values.
根据您在product_detail.html
模板中使用product
变量的方式,这可能不会导致显示错误消息,而只会显示空值。
When dealing with redirects, you might accidentally create a redirect loop, by having URL A return a redirect that points to URL B which returns a redirect to URL A, and so on. Most HTTP clients detect this kind of redirect loop and will display an error message after a number of requests.
在处理重定向时,您可能会意外地创建重定向循环,方法是让URL A返回指向URL B的重定向,该URL指向URL B的重定向,依此类推。 大多数HTTP客户端会检测到这种重定向循环,并在发出大量请求后显示错误消息。
Unfortunately, this kind of bug can be tricky to spot because everything looks fine on the server side. Unless your users complain about the issue, the only indication that something might be wrong is that you’ve got a number of requests from one client that all result in a redirect response in quick succession, but no response with a 200 OK
status.
不幸的是,发现这种错误可能很棘手,因为在服务器端一切看起来都很好。 除非您的用户抱怨此问题,否则唯一可能表明有问题的迹象是,您从一个客户端收到了许多请求,这些请求均导致快速连续的重定向响应,但没有响应(状态为200 OK
。
Here’s a simple example of a redirect loop:
这是重定向循环的一个简单示例:
def def a_viewa_view (( requestrequest ):
):
return return redirectredirect (( 'another_view''another_view' )
)
def def another_viewanother_view (( requestrequest ):
):
return return redirectredirect (( 'a_view''a_view' )
)
This example illustrates the principle, but it’s overly simplistic. The redirect loops you’ll encounter in real-life are probably going to be harder to spot. Let’s look at a more elaborate example:
这个例子说明了原理,但是过于简单了。 在现实生活中遇到的重定向循环可能会更难发现。 让我们看一个更详细的例子:
featured_products_view()
fetches all featured products, in other words Product
instances with .featured
set to True
. If only one featured product exists, it redirects directly to product_view()
. Otherwise, it renders a template with the featured_products
queryset.
.featured
featured_products_view()
获取所有特色产品,即.featured
设置为True
Product
实例。 如果仅存在一个特色产品,它将直接重定向到product_view()
。 否则,它将渲染带有featured_products
的模板。
The product_view
looks familiar from the previous section, but it has two minor differences:
product_view
在上一节中看起来很熟悉,但是有两个细微的差别:
Product
that is in stock, indicated by having .in_stock
set to True
.featured_products_view()
if no product is in stock.Product
,将.in_stock
设置为True
。 featured_products_view()
。 This logic works fine until your shop becomes a victim of its own success and the one featured product you currently have goes out of stock. If you set .in_stock
to False
but forget to set .featured
to False
as well, then any visitor to your feature_product_view()
will now be stuck in a redirect loop.
在您的商店成为自己成功的受害者并且您当前拥有的一项特色产品缺货之前,这种逻辑一直有效。 如果将.in_stock
设置为False
但也忘记将.featured
设置为False
,那么feature_product_view()
任何访问者现在都将停留在重定向循环中。
There is no bullet-proof way to prevent this kind of bug, but a good starting point is to check if the view you are redirecting to uses redirects itself.
没有防止这种错误的防弹方法,但是一个很好的起点是检查要重定向到的视图是否使用重定向本身。
Permanent redirects can be like bad tattoos: they might seem like a good idea at the time, but once you realize they were a mistake, it can be quite hard to get rid of them.
永久重定向可能就像坏纹身一样:在当时可能看起来是个好主意,但是一旦您意识到它们是一个错误,就很难摆脱它们。
When a browser receives a permanent redirect response for a URL, it caches this response indefinitely. Any time you request the old URL in the future, the browser doesn’t bother loading it and directly loads the new URL.
当浏览器收到URL的永久重定向响应时,它将无限期缓存该响应。 将来您每次请求旧的URL时,浏览器都不会费心加载它,而是直接加载新的URL。
It can be quite tricky to convince a browser to load a URL that once returned a permanent redirect. Google Chrome is especially aggressive when it comes to caching redirects.
要说服浏览器加载一旦返回永久重定向的URL,可能会非常棘手。 对于缓存重定向,Google Chrome尤其具有攻击性。
Why can this be a problem?
为什么会出现问题?
Imagine you want to build a web application with Django. You register your domain at myawesomedjangowebapp.com
. As a first step, you install a blog app at https://myawesomedjangowebapp.com/blog/
to build a launch mailing list.
假设您想使用Django构建Web应用程序。 您在myawesomedjangowebapp.com
注册您的域。 第一步,请在https://myawesomedjangowebapp.com/blog/
上安装博客应用,以构建启动邮件列表。
Your site’s homepage at https://myawesomedjangowebapp.com/
is still under construction, so you redirect to https://myawesomedjangowebapp.com/blog/
. You decide to use a permanent redirect because you heard that permanent redirects are cached and caching make things faster, and faster is better because speed is a factor for ranking in Google search results.
您网站https://myawesomedjangowebapp.com/
的主页仍在建设中,因此您重定向到https://myawesomedjangowebapp.com/blog/
。 您之所以决定使用永久重定向,是因为您听说了永久重定向已被缓存,并且缓存使事情变得更快,而更快则更好,因为速度是影响Google搜索结果排名的因素。
As it turns out, you’re not only a great developer, but also a talented writer. Your blog becomes popular, and your launch mailing list grows. After a couple of months, your app is ready. It now has a shiny homepage, and you finally remove the redirect.
事实证明,您不仅是一名出色的开发人员,还是一位才华横溢的作家。 您的博客变得流行,并且您的启动邮件列表也在增长。 几个月后,您的应用已准备就绪。 现在,它有一个闪亮的主页,您终于删除了重定向。
You send out an announcement email with a special discount code to your sizeable launch mailing list. You lean back and wait for the sign-up notifications to roll in.
您将带有特殊折扣代码的公告电子邮件发送到较大的启动邮件列表。 您向后倾斜并等待注册通知到来。
To your horror, your mailbox fills with messages from confused visitors who want to visit your app but are always being redirected to your blog.
令您感到恐惧的是,您的邮箱中充满了来自想要访问您的应用程序但总是被重定向到您的博客的困惑访问者的消息。
What has happened? Your blog readers had visited https://myawesomedjangowebapp.com/
when the redirect to https://myawesomedjangowebapp.com/blog/
was still active. Because it was a permanent redirect, it was cached in their browsers.
发生了什么事? 当重定向到https://myawesomedjangowebapp.com/blog/
的重定向仍处于活动状态时,您的博客读者已访问https://myawesomedjangowebapp.com/
。 由于它是永久重定向,因此已缓存在他们的浏览器中。
When they clicked on the link in your launch announcement mail, their browsers never bothered to check your new homepage and went straight to your blog. Instead of celebrating your successful launch, you’re busy instructing your users how to fiddle with chrome://net-internals
to reset the cache of their browsers.
当他们单击启动公告邮件中的链接时,他们的浏览器从不费心去检查您的新主页,而直接进入您的博客。 除了忙于成功启动之外,您还忙于指示用户如何摆弄chrome://net-internals
来重置其浏览器的缓存。
The permanent nature of permanent redirects can also bite you while developing on your local machine. Let’s rewind to the moment when you implemented that fateful permanent redirect for myawesomedjangowebapp.com.
永久重定向的永久性质也会在您在本地计算机上进行开发时咬住您。 让我们倒退到为myawesomedjangowebapp.com实施该重要永久重定向的时刻。
You start the development server and open http://127.0.0.1:8000/
. As intended, your app redirects your browser to http://127.0.0.1:8000/blog/
. Satisfied with your work, you stop the development server and go to lunch.
您启动开发服务器并打开http://127.0.0.1:8000/
。 如预期的那样,您的应用会将您的浏览器重定向到http://127.0.0.1:8000/blog/
。 对您的工作感到满意之后,您就停止了开发服务器并去吃午饭。
You return with a full belly, ready to tackle some client work. The client wants some simple changes to their homepage, so you load the client’s project and start the development server.
您满腹回来,准备应付一些客户工作。 客户端希望对其主页进行一些简单的更改,因此您可以加载客户端的项目并启动开发服务器。
But wait, what is going on here? The homepage is broken, it now returns a 404! Due to the afternoon slump, it takes you a while to notice that you’re being redirected to http://127.0.0.1:8000/blog/
, which doesn’t exist in the client’s project.
但是,等等,这是怎么回事? 主页已损坏,现在返回404! 由于下午的不景气,您可能需要一段时间才能注意到您已重定向到http://127.0.0.1:8000/blog/
,该地址在客户端项目中不存在。
To the browser, it doesn’t matter that the URL http://127.0.0.1:8000/
now serves a completely different application. All that matters to the browser is that this URL once in the past returned a permanent redirect to http://127.0.0.1:8000/blog/
.
对于浏览器,URL http://127.0.0.1:8000/
现在可以提供完全不同的应用程序,这无关紧要。 对浏览器而言,最重要的是该URL过去曾经返回永久重定向到http://127.0.0.1:8000/blog/
。
The takeaway from this story is that you should only use permanent redirects on URLs that you’ve no intention of ever using again. There is a place for permanent redirects, but you must be aware of their consequences.
从这个故事可以得出的结论是,您应该仅对不打算再次使用的URL使用永久重定向。 有一个永久重定向的地方,但是您必须意识到它们的后果。
Even if you’re confident that you really need a permanent redirect, it’s a good idea to implement a temporary redirect first and only switch to its permanent cousin once you’re 100% sure everything works as intended.
即使您确信确实需要永久重定向,还是最好先实施一个临时重定向,并且只有在100%确定一切都能按预期进行后,才切换到其永久表亲。
From a security perspective, redirects are a relatively safe technique. An attacker cannot hack a website with a redirect. After all, a redirect just redirects to a URL that an attacker could just type in the address bar of their browser.
从安全角度来看,重定向是一种相对安全的技术。 攻击者无法通过重定向来入侵网站。 毕竟,重定向仅重定向到攻击者可以在其浏览器的地址栏中键入的URL。
However, if you use some kind of user input, like a URL parameter, without proper validation as a redirect URL, this could be abused by an attacker for a phishing attack. This kind of redirect is called an open or unvalidated redirect.
但是,如果您使用某种类型的用户输入(例如URL参数)而没有正确验证作为重定向URL,则攻击者可能会将其滥用为网络钓鱼攻击。 这种重定向称为开放或未验证的重定向 。
There are legitimate use cases for redirecting to URL that is read from user input. A prime example is Django’s login view. It accepts a URL parameter next
that contains the URL of the page the user is redirected to after login. To redirect the user to their profile after login, the URL might look like this:
重定向到从用户输入读取的URL的合法用例是存在的。 一个很好的例子是Django的登录视图。 它next
接受一个URL参数,其中包含用户登录后重定向到的页面的URL。 要将用户登录后重定向到其个人资料,URL可能如下所示:
https://myawesomedjangowebapp.com/login/?next=/profile/
https://myawesomedjangowebapp.com/login/?next=/profile/
Django does validate the next
parameter, but let’s assume for a second that it doesn’t.
Django确实会验证next
参数,但让我们假设它不会。
Without validation, an attacker could craft a URL that redirects the user to a website under their control, for example:
未经验证,攻击者可能会制作一个将用户重定向到其控制下的网站的URL,例如:
The website myawesomedjangowebapp.co
might then display an error message and trick the user into entering their credentials again.
然后,网站myawesomedjangowebapp.co
可能会显示一条错误消息,并欺骗用户再次输入其凭据。
The best way to avoid open redirects is to not use any user input when building a redirect URL.
避免打开重定向的最佳方法是在构建重定向URL时不使用任何用户输入。
If you cannot be sure that a URL is safe for redirection, you can use the function django.utils.http.is_safe_url()
to validate it. The docstring explains its usage quite well:
如果不能确定URL重定向的安全性,则可以使用函数django.utils.http.is_safe_url()
进行验证。 该文档字符串很好地解释了其用法:
is_safe_url(url, host=None, allowed_hosts=None, require_https=False)
is_safe_url(url, host=None, allowed_hosts=None, require_https=False)
Return
True
if the url is a safe redirection (i.e. it doesn’t point to a different host and uses a safe scheme). Always returnFalse
on an empty url. Ifrequire_https
isTrue
, only ‘https’ will be considered a valid scheme, as opposed to ‘http’ and ‘https’ with the default,False
. (Source)如果url是安全的重定向(即,它不指向其他主机并且使用安全的方案),则返回
True
。 始终在空网址上返回False
。 如果require_https
为True
,则仅将'https'视为有效方案,而不是默认值为False
'http'和'https'。 ( 来源 )
Let’s look at some examples.
让我们看一些例子。
A relative URL is considered safe:
相对网址被认为是安全的:
>>> >>> # Import the function first.
# Import the function first.
>>> >>> from from django.utils.http django.utils.http import import is_safe_url
is_safe_url
>>>
>>>
>>> >>> is_safe_urlis_safe_url (( '/profile/''/profile/' )
)
True
True
A URL pointing to another host is generally not considered safe:
指向另一个主机的URL通常不被认为是安全的:
A URL pointing to another host is considered safe if its host is provided in allowed_hosts
:
如果在allowed_hosts
提供了指向另一个主机的URL,则认为该主机是安全的:
>>> >>> is_safe_urlis_safe_url (( 'https://myawesomedjangowebapp.com/profile/''https://myawesomedjangowebapp.com/profile/' ,
,
... ... allowed_hostsallowed_hosts == {{ 'myawesomedjangowebapp.com''myawesomedjangowebapp.com' })
})
True
True
If the argument require_https
is True
, a URL using the http
scheme is not considered safe:
如果参数require_https
为True
,则认为使用http
方案的URL不安全:
This wraps up this guide on HTTP redirects with Django. Congratulations: you have now touched on every aspect of redirects all the way from the low-level details of the HTTP protocol to the high-level way of dealing with them in Django.
本文总结了有关使用Django进行HTTP重定向的指南。 恭喜:您现在已经触及了重定向的各个方面,从HTTP协议的低级详细信息一直到Django中处理它们的高级方法。
You learned how an HTTP redirect looks under the hood, what the different status codes are, and how permanent and temporary redirects differ. This knowledge is not specific to Django and is valuable for web development in any language.
您了解了HTTP重定向的外观,不同的状态代码是什么以及永久和临时重定向的不同之处。 该知识不是Django特有的,对于任何语言的Web开发都是有价值的。
You can now perform a redirect with Django, either by using the redirect response classes HttpResponseRedirect
and HttpResponsePermanentRedirect
, or with the convenience function django.shortcuts.redirect()
. You saw solutions for a couple of advanced use cases and know how to steer clear of common pitfalls.
现在,您可以使用Django来执行重定向,方法是使用重定向响应类HttpResponseRedirect
和HttpResponsePermanentRedirect
,或者使用便利函数django.shortcuts.redirect()
。 您看到了一些高级用例的解决方案,并且知道如何避免常见的陷阱。
If you have any further question about HTTP redirects leave a comment below and in the meantime, happy redirecting!
如果您对HTTP重定向还有其他疑问,请在下面留下评论,同时,祝您重定向愉快!
django.http.HttpResponseRedirect
django.shortcuts.render()
django.views.generic.base.RedirectView
django.http.HttpResponseRedirect
django.shortcuts.render()
django.views.generic.base.RedirectView
翻译自: https://www.pybloggers.com/2018/08/the-ultimate-guide-to-django-redirects/
django重定向