登录后尝试将用户名添加到 url 时收到 NoReverseMatch 错误

Posted

技术标签:

【中文标题】登录后尝试将用户名添加到 url 时收到 NoReverseMatch 错误【英文标题】:Receiving a NoReverseMatch error while trying to add the username to the url after login 【发布时间】:2017-05-28 06:17:50 【问题描述】:

当用户点击“登录”时,我希望他们登录并重定向到即 www.exampledomain.com/accounts/usernameGoesHere/

这是我的***网址:

from django.conf.urls import url, include
from django.contrib import admin

# Namespace URLs
app_name = "pto_request"

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^accounts/', include('accounts.urls')),
]

这里是帐户的网址:

from django.conf.urls import url
from django.contrib.auth.decorators import login_required
from accounts.views import (login_view, register_view, logout_view)
from . import views

app_name = 'accounts'

urlpatterns = [
    # root url will look like www.website.com/accounts/

    url(r'^login/$', login_view, name='login'),
    url(r'^logout/$', logout_view, name='logout'),
    url(r'^register/$', register_view, name='register'),
    url(r'^(?P<username>[0-9a-zA-Z._]+)/$', login_required(views.IndexView.as_view()), name = 'index'),
]

这是我的登录视图:

def login_view(request):
    title = "Login"
    user_form = UserLoginForm(request.POST or None)
    if user_form.is_valid():
        username = user_form.cleaned_data.get('username')
        password = user_form.cleaned_data.get('password')
        user = authenticate(username=username, password=password)
        login(request, user)
        return redirect(reverse('accounts:index', args=[username]))
    return render(request, 'form.html', 'user_form':user_form, 'title':title)

最后这是我收到的错误的回溯日志:

Environment:


Request Method: GET
Request URL: http://localhost:8000/accounts/FlashBanistan/

Django Version: 1.10.5
Python Version: 3.5.2
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'crispy_forms',
 'datetimewidget',
 'accounts']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.locale.LocaleMiddleware']


Template error:
In template C:\django projects\PTO\accounts\templates\accounts\index.html, error at line 0
   Reverse for 'index' with arguments '()' and keyword arguments '' not found. 1 pattern(s) tried: ['accounts/(?P<username>[0-9a-zA-Z._]+)/$']   1 : % extends 'base.html' %
   2 : % load crispy_forms_tags %
   3 : 
   4 : % block content %
   5 : 
   6 :  form.media 
   7 : 
   8 : 
   9 : <div class="container">
   10 :   <div id="calendar">


Traceback:

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\exception.py" in inner
  39.             response = get_response(request)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\base.py" in _get_response
  217.                 response = self.process_exception_by_middleware(e, request)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\base.py" in _get_response
  215.                 response = response.render()

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\response.py" in render
  109.             self.content = self.rendered_content

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\response.py" in rendered_content
  86.         content = template.render(context, self._request)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\backends\django.py" in render
  66.             return self.template.render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in render
  208.                     return self._render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in _render
  199.         return self.nodelist.render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in render
  994.                 bit = node.render_annotated(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in render_annotated
  961.             return self.render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\loader_tags.py" in render
  174.         return compiled_parent._render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in _render
  199.         return self.nodelist.render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in render
  994.                 bit = node.render_annotated(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in render_annotated
  961.             return self.render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\defaulttags.py" in render
  315.                 return nodelist.render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in render
  994.                 bit = node.render_annotated(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py" in render_annotated
  961.             return self.render(context)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\defaulttags.py" in render
  439.             url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\urls\base.py" in reverse
  91.     return force_text(iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs)))

File "C:\Users\achesley\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\urls\resolvers.py" in _reverse_with_prefix
  392.             (lookup_view_s, args, kwargs, len(patterns), patterns)

Exception Type: NoReverseMatch at /accounts/FlashBanistan/
Exception Value: Reverse for 'index' with arguments '()' and keyword arguments '' not found. 1 pattern(s) tried: ['accounts/(?P<username>[0-9a-zA-Z._]+)/$']

【问题讨论】:

你不能从 login_view 'redirect()' 他们吗? 为什么你不能从 login_view 'return redirect("accounts/%s" % username)'? 你的代码看起来不安全,顺便说一句;在您执行 login() 时,用户可能是 None。 像稳定一样安全还是像安全一样安全?我不能只返回您输入的内容,因为我的网址未设置为接受字符串。 为什么还要附加用户名。在随后的帐户视图中,您不能从 request.user 获得该信息吗? 【参考方案1】:

第 1 步。将您的 index 网址移到最后,并给它一个仅接受用户名的模式。将index url 移到最后很重要,否则它将覆盖同一 urls 文件中的所有其他 url,例如,loginlogout

app_name = 'accounts'

urlpatterns = patterns(
    '',
    url(r'^login/', login_view, name='login'),
    url(r'^logout/', logout_view, name='logout'),
    url(r'^register/', register_view, name='register'),
    #
    # +------------ this url should come at last !!!!
    # |
    # v
    url(r'^(?P<username>[0-9a-zA-Z._]+)/$', login_required(views.IndexView.as_view()), name = 'index'), name = 'index'),
)

第 2 步。redirect 使用登录用户名发送到您的 index 网址。

return redirect(reverse('accounts:index', args=(username, )))

EDIT 2 修复模板错误

根据您的堆栈跟踪,您的模板中发生了错误,django 无法反转index 的网址。检查模板中的代码后,我发现,您调用了一个以accounts:index 为参数的url 函数,但没有在方法调用中指定用户名kwarg。

所以你可以用下面的代码修复错误:

% if user %
<li><a href="% url 'accounts:index' user.username %"><span class="glyphicon glyphicon-user"></span>  user.username </a></li>
% endif %

【讨论】:

哇,我不知道我需要多长时间才能找到这个错误。我会在早上进行更多研究,但是错误堆栈中是否有任何东西可以将我指向这个方向?我想学习如何更好地解析错误。 我专注于堆栈跟踪......它说模板错误......所以它一定是在你的模板中使用错误的 url.. 所以最后我得到了这个缺陷...... 如果您想编辑您发布的答案以反映您的发现,我会接受它作为答案。【参考方案2】:

另一种方法是将用户名作为查询字符串添加到重定向函数中。这样您就不必更改您的网址:

return redirect("/accounts/?username=%s" % user.username)

此外,您可以在视图中从request.user 获取用户(无需将其添加到 url),这是我推荐的——除非出于审美目的,您希望在 url 中使用它。

这是另一个登录功能供参考,它修复了您问题的 cmets 中讨论的一些问题:

def login(request):

    username = request.POST.get('username')
    password = request.POST.get('password')
    if username and password:

        # Make sure its an active user, or else return an error message.
        user = authenticate(username=username, password=password)
        if user is not None and user.is_active:
            auth_login(request, user)
            next = request.session.get('next', 'root')
            return redirect(next)
        else:
            messages.warning(request, "Invalid username / password.")

    return render(request, 'login.html')

【讨论】:

【参考方案3】:

Django 的 url 接受模式,也就是说,您可以为主页设置一个 url,例如:

url(r'^(?P<username>[a-zA-Z]*)$', views.userhome, name = 'index'),

在您的用户的索引视图中,您将从 url 获得一个变量,因此函数(与基于类的视图相同)将如下所示:

def userhome(request, username):

要使用这个url,你可以使用reverse函数:

#after login...
return redirect(revers('index', args=[username]))

这里有一些有用的提示:

    最好在您的views.py 中编写您的装饰器,因为在您的urls.py 中编写会使它过于混乱。 尝试使用reverse function 用户获取网址,而不是直接在代码中编写

关于reverse和url config的更多信息,您可以参考Django's doc。

【讨论】:

以上是关于登录后尝试将用户名添加到 url 时收到 NoReverseMatch 错误的主要内容,如果未能解决你的问题,请参考以下文章

登录django后如何将用户重定向到用户特定的url?

登录后 Spring Boot 重定向到请求的 URL

HttpListener“访问被拒绝”,尝试将 url 添加到 ACL

登录后的预期 URL 重定向 + 默认重定向?

如何在http请求角度添加令牌

Vue组件收到数据后如何更新