Django基础(14): 通过next参数实现登录后跳转回到前一页的3种方法

在实际Python web开发过程中,我们经常会碰到这样的应用场景。当用户试图访问某个页面或评论某个页面时,我们会要求其先登录,然后在用户在登录后自动跳转到用户试图访问的页面。小编我今天就来总结下Django中如何实现用户登录后跳转回前一页的几种方法,希望对大家有所帮助。

Django基础(14): 通过next参数实现登录后跳转回到前一页的3种方法_第1张图片

 

方法一: 静态模板中手动添加next参数实现跳转

假如我们负责管理用户注册登录的app叫myaccount, 其包括下面4个urls。我们要稍后用到它们。

from django.urls import re_path
from . import views

app_name = 'myaccount'
urlpatterns = [
    re_path(r'^account/register/$', views.register, name='account_register'),
    re_path(r'^account/login/$', views.login, name='account_login'),
    re_path(r'^user/(?P\d+)/profile/$', views.profile, name='profile'),
    re_path(r'^logout/$', views.logout, name='account_logout'),
]

 

这时静态模板中我们可以手动添加next参数,指向跳转页面链接。比如下例代码中,用户登录后会自动跳转到添加文章页面(blog:article_create)。

{% if request.user.is_authenticated %}

添加文章

{% else %}

登录后再添加文章。

 {% endif %} {% endblock %}

上面代码等同于下段代码。区别在于一个使用了命名的url,一个使用了硬编码的url(小编并不推荐硬编码,因为其不利于传递参数)。

{% if request.user.is_authenticated %}

添加文章

{% else %}

登录后再添加文章。

 {% endif %} {% endblock %}

或者

{% if request.user.is_authenticated %}

添加文章

{% else %}

登录后再添加文章。

 {% endif %} {% endblock %}

我们负责登录的视图login函数如下所示,该函数很重要的一件事就是处理通过next参数传递过来的跳转链接。当有next参数时,登录后跳转到next指向页面。如果没有next参数时,用户登录后跳转到profile页面。下面这段代码阅读性很高,请仔细体会。

def login(request):

    next = request.GET.get('next', '')

    if request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']

            user = auth.authenticate(username=username, password=password)

            if user is not None and user.is_active:
                auth.login(request, user)
                if  next == "":
                    return HttpResponseRedirect(reverse('myaccount:profile', args=[user.id]))
                else:
                    return HttpResponseRedirect(next)

            else:
                # 登陆失败
               return render(request, 'account/login.html', {'form': form,})
    else:
        form = LoginForm()

    return render(request, 'account/login.html', {'form': form})

那么问题来了,本例中我们明确知道客户登录后要跳转到创建文章(article_create)页面,所以可以直接在模板中通过next指定跳转链接。如果我们不知道用户尝试访问的前一个页面是什么,我们该如何操作呢?这时我们可以用request.path获取前一页面,如下所示。这是目前最好的解决方案。

登录后再访问。

 

如果URL里还含有参数(如?page=10或q=key), 可以使用request.get_full_path。

如果你使用django-allauth负责用户注册登录, 你可以直接使用{% url 'account_login' %}获取登录链接,前面不需要加myaccount:。

 

方法二: 使用login_required装饰器

用户尝试访问的页面总是对应某个视图,这时我们可以给这个视图加上login_required装饰器。对于基于函数的视图(Functional Based View, 以def开头), 你只需要在函数头部加上@login_required即可。

from django.contrib.auth.decorators import login_required

@login_required
def article_detail(request, pk):
    ...

login_required主要做以下事情。使用login_required前请确保你在settings.ply里设置了LOGIN_URL。

  • 当用户没有登录时,先转向包含settings.LOGIN_URL和next参数的绝对路径,例如/accounts/login/?next=/blog/article/15/。用户登录后会自动跳转到/blog/article/15/。

  • 如果用户已登录,直接显示/blog/article/15/

如果你使用自定义的用户管理app实现登录,你还需要修改视图中的login函数来处理url传递过来的next参数(见前文login函数代码),否则不会实现跳转。如果你使用Django自带的Auth登录模块或Django-allauth登录模块,你则不需要编写自己的login函数来处理next参数,因为它们可以自动处理next传递的参数并实现跳转。

 

当你使用基于类的视图(Class Based Views, 以class开头)时,你需要按如下方法使用method_decorator的这个装饰器。其作用是把类伪装成函数,然后再应用login_required这个装饰器。

from django.utils.decorators import method_decorator

@method_decorator(login_required, name='dispatch')
class ArticleDetailView(DetailView):
    model = Article

方法三: 视图views.py中实现跳转

在视图views.py中你可以使用HttpResponseDirect, redirect和reverse方法实现跳转(如下代码所示)。更多内容见Django基础(10): URL重定向的HttpResonseDirect, redirect和reverse方法详解。

def my_review(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/accounts/login/?next=/blog/article/15/')
    else:
        return HttpResponseRedirect('/blog/article/15/')

该方法的最大弊端是你需要知道用户之前尝试访问的urls是哪个,所以并不推荐。

 

小结

有多种方法可以实现用户在登录后跳转回前一页。小编我更推荐静态模板自定义next参数,其次是使用login_required装饰器。掌握了这些登录跳转的方法,我们就可以灵活地控制用户的访问权限和自由跳转了。当然Django自带的Permission系统更强大,我会稍后长文介绍,欢迎关注。如果对本文代码有任何不懂的地方或疑问,欢迎在评论区留言啊。如果你喜欢小编的文章,可以点击 微信右上角"..."加入收藏以后再用哦。

 

大江狗

2018.8.15

你可能感兴趣的:(Django,Django基础连载)