了解 Django Class-Based(DetailView 和 View)

Understanding Django Class-Based (DetailView and View)

我正在将一些基于函数的视图转换为基于 Class 的视图,以使我的视图更具可读性。但是我不太了解 DetailView 的使用以及如何将它实际集成到我的代码中以便将 slug 传递到我的函数中。

目前,我正在使用 View 并将 slug 传递到我的函数中,如下所示:

#urls.py
path('preview/<slug:slug>/', views.Preview.as_view(), name='toPreview')

#views.py 
@method_decorator(auth0_login_required, name='dispatch')
class Preview(View):
    template_name = 'authenticated/preview.html'

    @card_is_chosen
    def get(self, slug, request, *args, **kwargs): 
        person = get_object_or_404(Person, slug=slug, status=True)
        ...        
        return render(request, self.template_name, {...})

我也不太确定这是否是最佳实践,如果是,那么 DetailView 提供什么?


编辑: 尝试使用评论中提到的 DetailView,我该如何解决这个错误?

#urls.py
path('preview/<slug:slug>/', views.Preview.as_view(), name='toPreview')

#views.py 
@method_decorator(auth0_login_required, name='dispatch')
class Preview(DetailView):
    model = Person
    template_name = 'preview.html'

    @card_is_chosen
    def get(self, request, *args, **kwargs): 
        print(slug) 
        #slug is not defined, how should I fetch slug parameter?
        ...

        return render(request, self.template_name, {...})

回溯:

File "C:\Users\...\Desktop\env\src\...\apps\businesscards\decorators.py", line 60, in wrap
    return function(self, request, slug, *args, **kwargs)
  File "C:\Users\...\Desktop\env\src\...\apps\businesscards\views.py", line 160, in get
    person = get_object_or_404(Person, slug=slug, status=True)
NameError: name 'slug' is not defined

由于您的 slug 字段名为 slug,您只需在详细视图中指定 modeltemplate_name。详细视图将负责获取带有该鼻涕虫的人。

from django.views.generic import DetailView

@method_decorator([auth0_login_required, card_is_chosen] name='dispatch')
class PersonDetailView(DetailView):
    model = Person
    template_name = 'authenticated/preview.html'

    def get_context_data(self, **kwargs):
        """
        get_context_data is one of the important hooks in generic class
        based views. It lets you add extra variables to the template context
        """
        context = super(PersonDetailView, self).get_context_data(**kwargs)
        context['extra'] = 'extra value'
        return context

在上面,我假设用card_is_chosen修饰dispatch方法是可以的。如果不是这种情况,您可以改为添加 method_decorator(card_is_chosen, name='get')。我添加了一个 get_context_data - 上面的代码不需要它,但它可能对你的问题中你没有显示的某些 ... 代码有用。

如果您重写 get 方法,我会使用通常的签名 def get(self, request, *args, **kwargs): 然后为 self.kwargs

获取 slug
def get(self, request, *args, **kwargs):
    slug = self.kwargs['slug']

通常应避免为通用 class-based-views 覆盖 getpost。您冒着失去功能或不得不复制代码的风险。通常有更具体的属性或方法可以覆盖。

最后,不要假设基于 class 的视图总是更好。就个人而言,我会发现以下 function-based-view 比您的 Preview 观点更容易阅读。

@auth0_login_required
@card_is_chosen
def person(request, slug):
    person = get_object_or_404(Person, slug=slug, status=True)
    template_name = 'authenticated/preview.html'
    ...
    return render(request, template_name, {...})

我们可以使用DetailView如下

from django.views.generic import DetailView

@method_decorator(login_required, name='dispatch')
@method_decorator(card_is_chosen, name='get')
class Preview(DetailView):
    template_name = 'authenticated/preview.html'

    def get_object(self):
        return get_object_or_404(Person, slug=self.kwargs['slug'], status=True)

使用 variable/name object

访问模板中的对象

好吧,使用 CBV 的优势在于您可以 re-use 来自其他 django CBV 或您自己的 classes/mixins 的功能。这导致有更多的 DRY 代码。

我已经写了一篇关于这个的冗长教程,我建议在开始使用 CBV 之前阅读它:https://spapas.github.io/2018/03/19/comprehensive-django-cbv-guide/

现在,在您的具体示例中:您很少需要从 View 继承——而是从 View 的子类继承,例如您提到的 DetailView。现在,您可以像这样实现 Preview 视图:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import DetailView


class Preview(LoginRequiredMixin, View):
    template_name = 'authenticated/preview.html'
    mode = Person

我不确定 @card_is_chosen 装饰器的作用,但上面的装饰器与您的示例具有相同的功能(我已经将 auth0_login_required 更改为 login_required 因为我也不知道不知道 auth0_login_required 做什么)。请注意,您不需要重新定义 get 也不需要调用任何代码来检索基于 slug 的对象实例。