3

I have a method inside a django class based view like called get_player_stats. From this method I want to call another method in the same class but I am unable to. Code is like below:

class ScoreView(TemplateView):

   def get_player_stats(request):
       player_id = request.GET.get(player_id, None)
       # compute  player stats

       #here I want to call like below:
       self.get_team_stats(player_id)

   def get_team_stats(self, player_id):
      #compute team stats

When I run this it says name 'self' is not defined

If I try def get_player_stats(self, request): it says missing 1 required positional argument: 'request'

If I try def get_player_stats(request, self): it says missing 1 required positional argument: 'self'

How can I call get_team_stats from get_player_stats?

This is very frustrating, any help is greatly appreciated

P.S: I call get_player_stats as an ajax call by defining a URL path as below:

url('score/get_player_stats', views.ScoreView.get_player_stats)

Then I call it using $.ajax with url: '/score/get_player_stats'

8
  • It is not how you define things, it is how you call things. Commented Jun 11, 2018 at 22:03
  • @WillemVanOnsem - I am very new to django. Can you please help by elaborating a bit? Commented Jun 11, 2018 at 22:04
  • 1
    Where do you call get_player_stats? (not get_team_stats)? Commented Jun 11, 2018 at 22:04
  • I would recommend extracting the get_player_stats logic to an external helper module function and then calling that from both views. Commented Jun 11, 2018 at 22:05
  • 2
    @UndefinedVariable: I think you use TemplateView the wrong way. The idea of a class-based view is that you can declare a template, queryset, etc. But the idea is that you can not simply call an arbitrary function. See here: docs.djangoproject.com/en/2.0/ref/class-based-views/base/… Commented Jun 11, 2018 at 22:09

1 Answer 1

10

I see here 2 problems:

  1. Misconceptions about class-based views in django
  2. Misconceptions about object- and class- methods in python

Let's look in more detail.

1. Django class-based views

It must be sound strange (especially for newcomers) but class-based view in django does not means that you bind methods of objects/classes to url-routes.

More so:

  • django.urls.path can use only functions of fn(request, *args, **kwargs)

  • Pythonic it's better explicite for self-param makes object-methods unusable for views (at least without "special magic").

So what the meaning of class-based views?

https://github.com/django/django/blob/2bc014750adb093131f77e4c20bc17ba64b75cac/django/views/generic/base.py#L48

In fact it's very simple:

  1. class-based view expose class method as_view
  2. as_view is a high-order function and not used directly in path/url calls.
  3. as_view constructs actual view function at runtime
  4. generated function is not very complicated too. Roughly speaking, it looks for existence of defined get/post/put/head-methods, calls them when they exists and raises exceptions when not exists.

So you can see that "one does not simply binds methods of class-view to url-routes in django".

It is a tool that can be hardly recommended for general cases, it works good in cases when this inflexibility is desirable.

2. object-,class-, static- methods

OK. Now the second problem.

Can we call from methods of class-based view other methods?

Yes we can but with some restrictions.

Let's look at one-file demo in django 2.0. (For 1.11 - %s/path/url/g)

from django.urls import path    
from django.http import HttpResponse
from django.utils.decorators import classonlymethod


# CASE 1: normal function - OK
def just_a_fun(request, **kwargs):
    context = kwargs if kwargs else {"method": "just a function"}
    return HttpResponse('method = %(method)s' % context)


class ViewClass(object):
    def get(self, request, **kwargs):
        return just_a_fun(request, **kwargs)

    # CASE 2: Object method - FAIL, not possible to use in `django.url.path`-calls
    def om_view(self, request):
        return self.get(request, **{"method": "object method"})

    # CASE 3: class method - OK
    @classmethod
    def cm_view(cls, request):
        return cls.get(cls, request, **{"method": "class method"})

    # CASE 4: static method - FAIL, not possible to call `cls.get` or `self.get`
    @staticmethod
    def sm_view(request):
        self = None  # This is a problem with static methods
        return self.get(self, request, **{"method": "static method"})

    # CASE 5: HOF-view, similar to django.views.generic.View.as_view - OK
    @classonlymethod
    def as_view(cls, **initkwargs):
        def view(request, **kwargs):
            self = cls(**initkwargs)  # Object construction
            self.request = request
            self.kwargs = kwargs
            return self.get(request, **{"method": "HOF as_view"})

        return view


urlpatterns = [
    path("just-a-fun", just_a_fun),  # OK
    path("object-method",
         ViewClass.om_view),  # Problem: redundant `self` for `path`
    path("class-method", ViewClass.cm_view),  # OK
    path('static-method',
         ViewClass.sm_view),  # Problem: not possible to call `get`
    path('hof-view', ViewClass.as_view()),  # OK. 
]

Summary:

  1. Plain functions are best in general
  2. Object methods are not usable (at least without some "special magic")
  3. Class methods: have no problems. But keep in mind that class methods can use only other class methods
  4. Static methods: OK for using in path/url calls but they can't use other methods of classes
  5. If you really really want to use OOP: you can do it in "django way" - create HOFs that will generate actual views functions at runtime. Look at django.views.generic source code for inspiration

...

I hope that must clear things up but questions, critique, corrections - you are welcome!

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, that was very helpful!
@UndefinedVariable Was it helpful as "it answered my puzzle" or "it gave me food for thought"? I'm asking you because I saw a lot of times: django seems for newcomer dead-simple and no-magic till he/she stumbles on Model/Form metaclass-magic

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.