0

More specifically, is the one more preferable to the other? I know views that extend ListView can maybe have more readable code (and less of it), but even then, function-based views can often be written in like 2 lines of code with everything outlined in them, including the template and the data passed into the template. What are the benefits of each?

  • 1
    Use whatever you are comfortable with. Class based would be the Django way function is a little more python script like. similar question was asked here https://stackoverflow.com/questions/14788181/class-based-views-vs-function-based-views – hansTheFranz Jan 11 '21 at 22:44
  • Thank you, I was confused because the official Django tutorial showed the generic views as something to learn, I thought that's how you do lists, but functions now just seem better to me. – PyrettaBlaze Jan 11 '21 at 23:36

1 Answers1

1

I think this problem refers to two different programming style/diagram, functional and OOP.

The best part of making use of Class-based View in Django, as the general OOP idea, is that you can inherit (and multi-inherit) from other classes, which makes your view much more extensive, and reusable on codes.

For example, you have a series of views which requires some data integrity check before the main process block, in a class-based view style you may write those data check code into a customized mixin used for multi-inheritance.

# 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):
    # ...

Here like to mention another example specifically ListView. As you know the built-in ListView provides pagination by default, you may see something like:

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

And then magically in your Html template, you got some context variables like page_obj, paginator and is_paginated, for example:

          <!-- 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 %}

What the heck is going on? If you check the source code then you will realize those are inside a get_context_data method, which will prepare those context variables to pass into your templates. Also, you can easily extend what you want to pass into your template by inheritance, for example:


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

Imagine if you need to write a function to provide this paginator feature, of course, it will be a good practice to understand more about the Paginator object and its methods, still, you are rebuilding the wheel to some extend.

The difficult part of class-based views is too abstract, this troubles many people including myself at the beginning, you have no idea why the code is so short and what is happening behind the scenes.

This requires you to read the source code of those built-in generic views, which may be hard at the beginning. While once you get used to it, you will understand not only how it works but also be possible to rewrite and extend it in your own way.

Functional programming is intuitive and more straightforward, you do not have to worry about those invisible abstracted part which determines the behavior, you can design a view function and put everything under control.

The cons are obvious, you cannot reuse those built-in class-based views, which have many nice functions and features. Those will reduce your time on writing everything in a giant function.

I know there are many controversies and personal preferences on this topic, personally, I will suggest trying to learn the class-based view. As your projects grow, make your code reusable will be very helpful and sometimes a life-saver. And I believe this experience will be a good asset for you when you learn other languages or frameworks in the future.

convers39
  • 312
  • 5
  • 12