Django - 登录后,将用户重定向到他的自定义页面 --> mysite.com/username

70

默认情况下,登录后Django会将用户重定向到一个账户/个人资料页面,或者如果您编辑LOGIN_REDIRECT_URL,则可以将用户发送到settings.py中指定的另一个页面。

这很好,但我希望用户(登录后)被重定向到一个自定义页面,该页面的链接看起来像这样:mysite.com/username。因此,在这种情况下,默认的账户/个人资料或LOGIN_REDIRECT_URL设置都不起作用,因为两者都是静态的。在我的情况下,地址的username部分针对每个用户都会更改。

有什么想法可以让用户登录后进入一个自定义的用户页面,其中地址中包含用户的名称,例如:mysite.com/username

9个回答

101

更简单的方法是通过从页面LOGIN_REDIRECT_URL进行重定向。要注意的关键点是用户信息会自动包含在请求中。

假设:

LOGIN_REDIRECT_URL = '/profiles/home'

而且你已经配置了一个urlpattern:

(r'^profiles/home', home),

那么,你只需要为视图home()编写以下代码:

from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required

@login_required
def home(request):
    return HttpResponseRedirect(
               reverse(NAME_OF_PROFILE_VIEW, 
                       args=[request.user.username]))

其中NAME_OF_PROFILE_VIEW是您正在使用的回调函数的名称。在Django-profiles中,NAME_OF_PROFILE_VIEW可以是'profiles_profile_detail'。


4
对于基于类的视图,怎么样? - User
@用户,“home”视图可以重定向到任何URL模式,无论它使用函数视图还是类视图。 - Alasdair
这个问题的唯一问题(可能对您来说不是问题)是,如果在登录的get中指定了?next=/someurl/,那么您将永远无法到达LOGIN_REDIRECT_URL,因此确保他们最终到达您想要的URL的唯一方法是实现自己的视图。 - Lehrian

16

我忘了提到我正在使用django附带的django.contrib.auth.views。在这种情况下,我可以使用上面描述的自定义URL吗? - avatar
1
我不确定您是否可以自定义auth.views.login到那个程度。话虽如此,我会编写自己的登录函数,就像我在上面链接的文档中所示的那样。 - Abid A

14
是的!在你的 settings.py 中定义以下内容。
LOGIN_REDIRECT_URL = '/your-path'

让 '/your-path' 成为一个简单的视图,查找self.request.user并执行所需逻辑以返回一个HttpResponseRedirect对象。

一种更好的方法是定义一个简单的URL,如'/simple',在那里执行查找逻辑。这样URL看起来更美观,省去了一些工作等。


9
如果您正在使用Django内置的 LoginView,它将next作为上下文,即"成功登录后重定向的URL。这也可能包含一个查询字符串。" (请参见文档)

此外,还有来自文档的:

"如果登录成功,视图将重定向到next参数指定的URL。如果未提供next,则重定向到settings.LOGIN_REDIRECT_URL(默认为 /accounts/profile/)。"

示例代码:

urls.py

from django.urls import path
from django.contrib.auth import views as auth_views

from account.forms import LoginForm # optional form to pass to view


urlpatterns = [
    ...

    # --------------- login url/view -------------------
    path('account/login/', auth_views.LoginView.as_view(
        template_name='login.html',  
        authentication_form=LoginForm, 
        extra_context={ 

            # option 1: provide full path
            'next': '/account/my_custom_url/', 

            # option 2: just provide the name of the url
            # 'next': 'custom_url_name',  
        },
    ), name='login'),

    ...
]

login.html

...

<form method="post" action="{% url 'login' %}">

  ...

  {# option 1 #}
  <input type="hidden" name="next" value="{{ next }}">

  {# option 2 #}
  {# <input type="hidden" name="next" value="{% url next %}"> #}

</form>

1
默认情况下,任何重定向到登录页面的视图都将保留next变量。如果用户直接登录到登录URL,则没有next,系统将默认为LOGIN_REDIRECT_URL。如果您需要特别处理它,建议使用extra_context={"next":mysite.com/username}来解决要求。 - Doogle
1
已在Django 2.2.5上进行了测试,您还需要在extra_context字典中指定redirect_authenticated_user=True,以使此解决方案起作用。 - cristian
@cristian 我相信 redirect_authenticated_useras_view 函数的一个单独参数(即它不在 extra_context 中)(请参见 https://docs.djangoproject.com/en/2.2/topics/auth/default/#django.contrib.auth.views.LoginView)。它控制已经认证的用户访问登录页面时会发生什么(将他们重定向到某个地方,就好像他们刚刚登录了一样,或者只是让他们访问该页面)。 - kimbo

7
当使用基于类的视图时,另一个选择是使用dispatch方法。 https://docs.djangoproject.com/en/2.2/ref/class-based-views/base/ 示例代码:
Settings.py
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'home'

urls.py

from django.urls import path
from django.contrib.auth import views as auth_views
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('login/', auth_views.LoginView.as_view(),name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

views.py

from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.views.generic import View
from django.shortcuts import redirect

@method_decorator([login_required], name='dispatch')
class HomeView(View):
    model = models.User

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return redirect('login')
        elif some-logic:
            return redirect('some-page') #needs defined as valid url
        return super(HomeView, self).dispatch(request, *args, **kwargs)

1

我实际上更喜欢@Stu和其他人提到的方法,即创建一个新的URL和一个视图,以便我们可以将重定向逻辑放在那里。这样更容易,用户还可以在浏览器中键入example.com/profile以重定向到他们在example.com/profile/username/上的个人资料。

但另一种不需要定义额外URL的方法是扩展LoginView,并使用配置文件视图的URL名称进行重定向。

假设我们有两个名为accountspages的应用程序,并且我们已经在pages应用程序中定义了配置文件页面,类似于这样:

# pages/views.py
from django.views.generic import View
from django.http import HttpResponse

class ProfileView(View):
    def get(self, request, username):
        return HttpResponse('Hello ' + username + '!')

以及URLConf:

# pages/urls.py
from django.urls import path
from .views import ProfileView

app_name = 'pages'
urlpatterns = [
    path('profile/<str:username>/', ProfileView.as_view(), name='profile')
]

请注意,我们必须定义app_name = 'pages',因为我们需要用它来引用pages应用程序的URL。
然后,在accounts应用程序中,我们扩展LoginView并添加重定向逻辑:
# accounts/views.py
from django.contrib.auth.views import LoginView
from django.urls import reverse

class CustomLoginView(LoginView):
    def form_valid(self, form):
        self.success_url_kwargs = {'username': form.cleaned_data['username']}
        return super().form_valid(form)

    def get_success_url(self):
        # 'pages:profile' refers to the 'profile' path in the 'pages' app.
        return reverse('pages:profile', kwargs=self.success_url_kwargs)

# accounts/urls.py
from django.urls import path, include
from .views import CustomLoginView

urlpatterns = [
    path('accounts/login/', CustomLoginView.as_view(), name='login'),
    path('accounts/', include('django.contrib.auth.urls'))
]

成功登录后,将调用form_valid()方法,并将我们要在个人资料URL中使用的参数添加到自定义类属性success_url_kwargs中。最后,调用return super().form_valid(form)首先登录用户,然后重定向到由get_success_url()方法(参见代码)给出的URL,该方法定义为返回我们想要的自定义URL。
请注意,在我们要访问accounts/login/时,我们在自定义登录URL之后包含了auth应用程序的URL。
另外,如果我们需要访问用户模型实例,可以调用form.get_user()。在某些情况下,这很有用。例如,如果用户使用电子邮件登录,我们需要他的用户名,则可以执行form.get_user().username

0
{% if redirect_field_value == None %}
<input type="hidden" name="{{ redirect_field_name }}" value="/LOGIN_REDIRECT_URL(instead of typing in settings.py file)/">
{% else %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{redirect_field_value}}">
{% endif %}

将此代码放置在登录html页面中。例如,如果您直接访问登录页面(例如:/accounts/login/),则“next”值将为None,即在登录后,它不知道要重定向到哪个页面,除非您在设置页面中指定“LOGIN_REDIRECT_URL”(例如:LOGIN_REDIRECT_URL=/dashboard/)。如果您在设置页面中指定了“LOGIN_REDIRECT_URL”,如示例所示,则在登录后,它将重定向到“/dashboard/”网址。

如果您需要访问另一个也需要登录才能查看的网址(例如:/items/)。因此,当您访问“localhost:8000/items/”时,它需要登录才能查看,它将重定向到“localhost:8000/accounts/login/?next=/items/”。这里的“next”值将是“items”,但问题是,由于您在设置页面中指定了“LOGIN_REDIRECT_URL”,因此它总是在登录后重定向到/dashboard/网址。

因此,上述HTML代码有助于重定向,如果“next”值为None,则它将转到我们指定为隐藏输入值的页面。如果“next”不为None,则它将根据“next”的值进行重定向。


您的回答可以通过添加更多支持性信息来改进。请进行[编辑]以添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案正确无误。您可以在帮助中心 中找到有关如何编写良好答案的更多信息。 - Community
你的回答可以通过添加更多支持信息来改进。请编辑并添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - jahantaila

0

对我来说它正在工作:

from django.shortcuts import redirect

return redirect('path/to/login/?next=/custompageurl/{}'.format(username))

0
最近开始学习Django,一直在寻找一个解决方案,发现了一个可能很有用的方法。
例如,如果使用默认重定向accounts/profile,那么可以创建一个视图,只使用用户名字段将其重定向到所选位置,如下所示:
def profile(request):
    name=request.user.username
    return redirect('-----choose where-----' + name + '/')

然后创建一个视图,在你的应用程序中捕获它,例如:

def profile(request, name):
    user = get_object_or_404(User, username=name)
    return render(request, 'myproject/user.html', {'profile': user})

urlpatterns 的捕获将如下所示:

url(r'^(?P<name>.+)/$', views.profile, name='user')

对我来说很有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接