Sjaak Trekhaak
Sjaak Trekhaak

Reputation: 4966

Django Class Based View - unexpected decorator behaviour

[edit] So it seems my code works fine, another piece of code + tiredness is the issue [/edit].

I have a decorator which does a simple check for a couple of required request keys.

def fields_required(*fields):
assert isinstance(fields, tuple), "Fields must be of type tuple."

def wrap_func(fn):

    def wrapper(cls, request, *args, **kwargs):
        print 'oh hi'
        missing_fields = []
        for field in fields:
            if not request.REQUEST.has_key(field):
                missing_fields.append(field)

        if len(missing_fields) > 0:
            #maybe do smth here
            return HttpResponseBadRequest()          

        return fn(cls, request, *args, **kwargs)
    return wrapper
return wrap_func

I expect a HTTP 403 Bad Request status code if one of the fields is missing, however the decorator never executes that code.

A basic representation of my view file:

class ViewA(View):

    @fields_required('name','api_key')
    def get(self, request, *args, **kwargs):
        # some logic

class ViewB(View):

    @fields_required('SHOULD_NEVER_SEE','THIS_STUFF')
    def get(self, request, *args, **kwargs):
        # some logic

When opening ViewA in the browser, the console output is as following:

('name', 'api_key')
('SHOULD_NEVER_SEE','THIS_STUFF')

I cannot understand why the decorator for ViewB is executed, and why there is no 'oh hi' in my console. Any insights?

Upvotes: 1

Views: 248

Answers (1)

Simeon Visser
Simeon Visser

Reputation: 122376

The decorator for ViewB is "executed" but not because you're viewing ViewA. It's because Python decorates the method when it executes the file itself. For example, the following prints b even though func is not called:

def deco(f):
    print 'b'
    def g():
        print 'c'
    return g

@deco
def func():
    print 'a'

Regarding the issue that 'oh hi' is not printed; could you try adding the decorator to dispatch instead of get (i.e., add the following to your views):

@method_decorator(fields_required('SHOULD_NEVER_SEE','THIS_STUFF'))
def dispatch(self, *args, **kwargs):
    pass

Upvotes: 1

Related Questions