Your decorator has an extra level of indirection which is throwing things off. When you do this:
@paginated_instance_method
def get_attending_users(self, *args, **kwargs):
return User.objects.filter(pk__in=self.attending_list)
You are doing this:
def get_attending_users(self, *args, **kwargs):
return User.objects.filter(pk__in=self.attending_list)
get_attending_users = paginated_instance_method(get_attending_users)
That is what decorators do. Note that paginated_instance_method
is called with get_attending_users
as its argument. That means that in your decorator, the argument default_page_size
is set to the function get_attending_users
. Your decorator returns the function wrap
, so get_attending_users
is set to that wrap
function.
Then when you then call Event().get_attending_users()
it calls wrap(self)
, where self
is your Event instance. wrap
is expecting the argument to be a function, and tries to return a new function wrapping that function. But the argument isn't a function, it's an Event
object, so functools.wrap
fails when trying to wrap it.
I have a hunch that what you're trying to do is this:
@paginated_instance_method()
def get_attending_users(self, *args, **kwargs):
return User.objects.filter(pk__in=self.attending_list)
That is, you want paginated_instance_method
to take an argument. But even if you want to use the default value of that argument, you still have to actually call paginated_instance_method
. Otherwise you just pass the method as the argument, which is not what paginated_instance_method
is expecting.
The reason it "worked" for a classmethod is that a classmethod takes the class as the first argument, and a class (unlike an instance) does have a __name__
attribute. However, I suspect that if you test it further you'll find it's not really doing what you want it to do, as it's still wrapping the class rather than the method.