[Django]-Possible to use mixins in function based views?

13๐Ÿ‘

โœ…

No.

First of all, it makes no sense. A mixin is something to mix into a class. You โ€œpatchโ€ certain functions in a mixin. But how would you do that on a function? A function can have attributes, but the idea is that typically a function does not do much with its attributes. It typically has no workflow where it calls attached functions. If you would be able to apply a mixin, that would mean that all of a sudden your function for example has a payment_method_view.get_queryset function. Although that could perhaps be useful, this is not really how functions are designed to be used.

A function typically encodes a form of computation, it is typically not used as some sort of collection that stores named attributes that interact with each other. A class is typically used for that: it contains elements (class attributes and methods), and they can interact with each other.

But furthermore it would result in a lot of problems. A function has no builtin inheritance mechanisms. So it means that if you applied to mixins that patched a function, then there would not be some method resolution order (MRO) that will โ€œguideโ€ super() calls, etc. As a result, very easily this would break.

Syntactically it makes no sense either. You simply defined a function that takes two parameters: request, and MyMixin. The fact that MyMixin happens to be the name of a class, is โ€“ according to Python โ€“ a coincidence. Function parameters define a scope, so it means that if you would use MyMixin in the function, you would refer to the value that corresponds to the given parameter.

What you typically do to change a function, is writing a decorator. A decorator is a function that takes as input the function, and alters the function, or creates a new one. In that case the decorated function is used. For example we can make a decorator @login_required:

from functools import wraps

def login_required(f):
    @wraps(f)
    def g(request, *args, **kwargs):
        if request.user.user.is_authenticated():
            return f(request, *args, **kwargs)
        else:
            return HttpResponse('Unauthorized', status=401)
    return g

Here we thus have defined a function login_required that takes as input a function f, and we construct a new function g. This function takes as parameters request, *args and **kwargs. First g checks if the user that is attached to the request is autheticated (has logged in), if that is the case, we call the given function f with the request, *args, and **kwargs. If not, we return a 401 exception (not autheticated).

Now we can apply our decorator to a function:

@login_required
def payment_method_view(request):
    # ...
    pass

So now Python will call our login_required function with payment_method_view as parameter, and the result (the g function) will take the place of the payment_method_view. We thus now require the user to be logged in before the original payment_method_view is called.

Leave a comment