Django - 注销视图自定义失败

Django - logout view customisation fail

虽然原问题被清除了,但有一个新的相关问题非常有趣:(请让我知道我的理论是否正确...)

请检查我下面的 url 模式:

from django.contrib.auth import views as auth_views
from boutique.models import Category
from django.urls import path, include
from . import views

app_name = 'users'
urlpatterns = [

    # to customise login view
    path('login/', auth_views.LoginView.as_view(extra_context = {'categories': Category.objects.get_categories_with_item()})),
    # path('login/', views.NewLoginView.as_view()),

    # to customise default logout view
    path('logout/', auth_views.LogoutView.as_view(), {'categories': Category.objects.get_categories_with_item()}),

    # include django authentication urls
    path('', include('django.contrib.auth.urls')),

你可能注意到有两种不同的方法可以传入 extra_context,有趣的是:LogoutView 上使用的方法不能用在 LoginView 上!!但是,LoginView 上使用的方法确实适用于 LogoutView

我认为可能的解释还有待你们证实,他们继承了不同的观点:

LoginView:

class LoginView(SuccessURLAllowedHostsMixin, FormView):
    """
    Display the login form and handle the login action.
    """
    form_class = AuthenticationForm
    authentication_form = None
    redirect_field_name = REDIRECT_FIELD_NAME
    template_name = 'registration/login.html'
    redirect_authenticated_user = False
    extra_context = None

    ...

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        current_site = get_current_site(self.request)
        context.update({
            self.redirect_field_name: self.get_redirect_url(),
            'site': current_site,
            'site_name': current_site.name,
            **(self.extra_context or {})
        })
        return context

LogoutView:

class LogoutView(SuccessURLAllowedHostsMixin, TemplateView):
    """
    Log out the user and display the 'You are logged out' message.
    """
    next_page = None
    redirect_field_name = REDIRECT_FIELD_NAME
    template_name = 'registration/logged_out.html'
    extra_context = None

    ...

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        current_site = get_current_site(self.request)
        context.update({
            'site': current_site,
            'site_name': current_site.name,
            'title': _('Logged out'),
            **(self.extra_context or {})
        })
        return context

我认为 LoginView 必须将 extra_context 作为位置参数传递给 .as_view() 的原因是它没有继承自 TemplateView:

class TemplateView(TemplateResponseMixin, ContextMixin, View):
    """
    Render a template. Pass keyword arguments from the URLconf to the context.
    """
    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

它有一个 get 方法来获取上下文数据...如果我没记错的话。

谁能证实一下?

我对 python 和 django 框架还很陌生。非常感谢!!!


原问题已回答

请在评论区查看答案--


我是 Django 的新手,为了将更多上下文传递给注销视图,我尝试了 2 种方法来自定义注销视图:

方法一:

from django.contrib.auth import views as auth_views
from boutique.models import Category

app_name = 'users'
urlpatterns = [
    ...
    path('logout/', auth_views.LogoutView.as_view(), {'categories': Category.objects.all()}),

    # I also tried this:
    # path('logout/', auth_views.LogoutView.as_view({'categories': Category.objects.all()}),


    # I also tried this: 
    # path('logout-customised-url/', auth_views.LogoutView.as_view(), {'categories': Category.objects.all()}),
    # This is working tho it wouldn't be automatically redirect to this path when logged out

方法二:

    ...
    path('logout/', views.NewLogoutView.as_view()),
    # NewLogoutView code below:

views.py

from boutique.models import Category
from django.contrib.auth.views import LogoutView


class NewLogoutView(LogoutView):

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Category.objects.all()
        return context

仍然无效,结果完全一样:如果正在使用自定义 url,例如 'logged-out/' 而不是 'logout/',然后您输入 url,它会呈现带有额外上下文的正确页面。但是,当用户正常注销时,不会转到页面...

有什么解决办法吗?谢谢!

您需要在 urls.py 中传递 extra_context 才能将额外的上下文发送到注销视图。阅读更多关于 passing extra context to a view from in url definition.

path(
    'logout/',
    auth_views.LogoutView.as_view(),
    {'extra_context':{'categories': Category.objects.all()}}
),

知道了!!问题出在我的urlpatterns的顺序上,原来是这样的:

urlpatterns = [

    # include django authentication urls
    path('', include('django.contrib.auth.urls')),

    # to customise default logout view
    path('logout/', auth_views.LogoutView.as_view(), {'categories': Category.objects.get_categories_with_item()}),

基于official doc: Authentication Viewsdjango.contrib.auth.urls包括许多url模式,例如:

accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']

因此,如果在定制之前申报,则优先考虑。所以:

urlpatterns = [

    # to customise default logout view
    path('logout/', auth_views.LogoutView.as_view(), {'categories': Category.objects.get_categories_with_item()}),


    # include django authentication urls
    path('', include('django.contrib.auth.urls')),

调换顺序,行得通。


致像我这样的菜鸟: 方法 1 确实有效。只需在视图后的 official doc 中传递额外的 context/argument 即可。

此外,我检查了 django.contrib.auth.views.LogoutView:

class LogoutView(SuccessURLAllowedHostsMixin, TemplateView):
    """
    Log out the user and display the 'You are logged out' message.
    """
    next_page = None
    redirect_field_name = REDIRECT_FIELD_NAME
    template_name = 'registration/logged_out.html'
    extra_context = None
    ...

extra_context 设置为 None 以便您添加额外的上下文。如果要对其进行子类化或简单地将位置参数传递给 .as_view() ,则易于定制——这意味着:

urlpatterns = [

    # to customise login view
    path('login/', auth_views.LoginView.as_view(extra_context = {'categories': Category.objects.get_categories_with_item()})),

]

`Loginview` has the same the same convenient settings...