Callable LazyObject?

87 views
Skip to first unread message

Jeremy Dunck

unread,
Mar 5, 2014, 6:05:15 PM3/5/14
to django-d...@googlegroups.com
I recently had a need for a LazyObject which was callable.  The __call__ meta method isn't forwarded to _wrapped, so it's an error to call, even if the underlying _wrapped does support it.

In my case, was trying to do the following:

User = SimpleLazyObject(lambda: get_user_model())

User()...

I patched LazyObject to make it happy:

def _a_call_(self, *args, **kwargs):
    if self._wrapped is empty:
        self._setup()
    return self._wrapped(*args, **kwargs)

LazyObject.__call__ = _a_call_.__get__(User)

Unfortunately, I then ran into a related problem -- by making LazyObject callable, anyone passing a lazy user, e.g. request.user, to the ORM would fall into the callable(value) branch:

That then caused a new User to be constructed rather than using the request.user.pk.

I see that callable criteria are deprecated there, but was wondering how people would feel about adding a branch before that:

if ...
elif isinstance(value, LazyObject):
  pass
elif callable(value):
  ...

That would allow request.user to still be used (as it no doubt widely is) even after LazyObject grows a callable (if its underlying object has one).


Luke Plant

unread,
Mar 6, 2014, 11:12:15 AM3/6/14
to django-d...@googlegroups.com
On 05/03/14 23:05, Jeremy Dunck wrote:

> if ...
> elif isinstance(value, LazyObject):
> pass
> elif callable(value):
> ...

My gut instinct is that if Django's template code has to be patched and
special cased to accommodate this change, there will be lots of other
code that needs to be patched too.

LazyObject is already pretty hairy without trying to get it to support
more things.

Also, it seems that normally there should be other solutions. In many
cases, instead of:

User = SimpleLazyObject(lambda: get_user_model())

you could use:

User = lambda **kwargs: get_user_model()(**kwargs)

...assuming that the only thing you need 'User' to do is to produce User
instances when you call it. (If you need it to be an actual class for
some reason, then this won't work - but in most cases I'd suggest that
the consuming code shouldn't need an actual class).

Regards,

Luke


--
"God demonstrates his love towards us in this, that while we were
still sinners, Christ died for us." (Romans 5:8)

Luke Plant || http://lukeplant.me.uk/

Jeremy Dunck

unread,
Mar 6, 2014, 12:36:50 PM3/6/14
to django-d...@googlegroups.com
(It's a change in the DB code, not the template, but your point stands.)

I think I agree with you that changing LazyObject is risky when there's a workaround and it would be difficult to address the risk of callable(LazyObject()) becoming true.

OK, thanks for feedback.


--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/53189E5F.7010306%40cantab.net.
For more options, visit https://groups.google.com/groups/opt_out.

Reply all
Reply to author
Forward
0 new messages