首页 > 解决方案 > 与普通的基于函数的视图相比,ListView 的优缺点是什么,反之亦然?(姜戈)

问题描述

更具体地说,一个比另一个更可取吗?我知道扩展 ListView 的视图可能有更多可读的代码(而且更少),但即便如此,基于函数的视图通常可以用两行代码编写,其中包含所有内容,包括模板和传递的数据进入模板。各有什么好处?

标签: pythonpython-3.xdjango

解决方案


我认为这个问题是指两种不同的编程风格/图表,功能和 OOP

作为一般 OOP 思想,在 Django 中使用基于类的视图的最佳部分是您可以从其他类继承(和多重继承),这使您的视图更加广泛,并且可在代码上重用。

例如,您有一系列views需要在主进程块之前进行一些数据完整性检查的class-based view样式,您可以将这些数据检查代码写入自定义mixin的用于多继承的.

# mixins.py
# inherit from login required mixin and add data integrity check
class PostDataCheckMixin(LoginRequiredMixin):
    def dispatch(self, request, *args, **kwargs):
        try:
            data = json.loads(request.body.decode())
        except:
            return JsonResponse({'res': 0, 'errmsg': 'Invalid data'})
        return super().dispatch(request, *args, **kwargs)

# views.py
class OrderProcessView(PostDataCheckMixin, View):
    def post(self, request, *args, **kwargs):
    # ...

class OrderPaymentView(PostDataCheckMixin, View):
    def post(self, request, *args, **kwargs):
    # ...

这里想具体提另一个例子ListView。如您所知,默认情况下内置ListView提供pagination,您可能会看到如下内容:

class ProductListView(ListView):
    model = ProductSKU
    context_object_name = 'products'
    template_name = 'shop/product-list.html'
    paginate_by = 3
    paginate_orphans = 1

然后神奇地在您的 Html 模板中,您得到了一些上下文变量,例如page_obj,paginatoris_paginated,例如:

          <!-- PAGINATION-->
          {% if is_paginated %}
          <nav aria-label="Page navigation">
            <ul class="pagination justify-content-center justify-content-lg-end">
              {% if page_obj.has_previous %}
              <!--...-->
              
              {% endif %}

              {% for num in paginator.page_range %}
              <li class="page-item {% if page_obj.number == num %} active {% endif %}">
                <a class="page-link" href="{% qs_url 'page' num request.GET.urlencode %}">{{ num }}</a>
              </li>
              {% endfor %}

              {% if page_obj.has_next %}
              <!--...-->
             
              {% endif %}
            </ul>
          </nav>
          {% endif %}

到底他妈发生了什么?如果您检查源代码,那么您将意识到它们在一个get_context_data方法中,该方法将准备将它们context variables传递到您的模板中。此外,您可以通过继承轻松扩展要传递到模板中的内容,例如:


class ProductListView(ListView):
# ...
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs) 
        # at this moment your 'context' variable already contains 'page_obj', 'paginator' etc.

        category_slug = self.kwargs.get('category_slug')
        if category_slug:
            category = category_slug.replace('-', ' ')
            context['category'] = category 
            # here you add a new context variable 'category' 
        return context

想象一下,如果您需要编写一个函数来提供此分页器功能,当然,更多地了解Paginator对象及其方法将是一个好习惯,但您仍在某种程度上重建轮子。

基于类的视图的难点太抽象了,这让包括我在内的很多人一开始就很困扰,你不知道为什么代码这么短,幕后发生了什么。

这需要你阅读那些内置通用视图的源代码,一开始可能很难。一旦你习惯了它,你不仅会理解它是如何工作的,而且还可以用你自己的方式重写和扩展它。

函数式编程更直观、更直接,你不必担心那些决定行为的不可见的抽象部分,你可以设计一个视图函数,让一切尽在掌握。

缺点很明显,你不能重用那些内置的基于类的视图,它们有很多不错的功能和特性。这些将减少你在一个巨大的函数中编写所有内容的时间。

我知道关于这个话题有很多争议和个人偏好,我个人建议尝试学习基于类的观点。随着项目的增长,使您的代码可重用将非常有帮助,有时甚至可以挽救生命。并且我相信,当您将来学习其他语言或框架时,这种经验将成为您的宝贵财富。


推荐阅读