On 26 huhti, 00:59, I wrote:
> Now, if there would be some way to avoid the dynamic model subclassing
> used by deferred loading then storing the set of deferred fields per
> instance would be more than welcome. One possibility might be defining
> Model.__getattr__. If you end up in __getattr__ and the value isn't
> present in the model's __dict__ but the attname is present in the
> model._state.deferred_fields, then you know to load it from DB. I
> assume there are some reasons why this wasn't done in the first
> place... Maybe descriptors for custom fields would break or the above
> mentioned direct __dict__ access case would fail?

I tried the above approach. It works, but there are some potential
problems:
  1. There is a need to alter __init__ signature (added a
__loaded_fields kwarg).
  2. There is now __getattr__ for Model, this will cause slowdown for
attribute access and hasattr in case the attribute searched isn't
found. For cases where the attribute is found there is no speed
difference (as __getattr__ is only called for no-found cases).
  3. Potential problems for descriptors: the descriptors need to be
programmed defensively, if the attribute isn't found from the
instance's __dict__, then AttributeError will need to be raised
instead of KeyError. See changes in fields/subclassing.py for an
example.
  4. Doing del obj.someattr or obj.__dict__.pop(someattr) then
accessing the same attr again will result in reload from DB instead of
AttributeError.

But on the other hand you get totally rid of the ugly dynamic
subclassing used by deferred loading. This will resolve some
longstanding bugs (like signals not working when using deferred
models).

No 1. above seems like the biggest problem. Personally I don't see
overridden __init__ methods very useful in the first place. This is
because there is no way to know if load from DB happened, or if this
was a regular init. And in addition the semantics of __init__ is
strange. The initialization might happen through *args, or through
**kwargs, or through both, and missing kwargs might be deferred or
not.

This is maybe going out of topic, but I would actually like to add a
new _from_db class method which does model construction by direct
__dict__ assignment. So, model loading from DB wouldn't go through
__init__ at all. The reasoning for this is to get rid of the weird
__init__ semantics. Another reason is that load from DB is just a form
of deserialization, and deserialization shouldn't go through __init__,
instead the object should be constructed manually. This is how normal
Python pickling works. Finally, this way is much faster, up to around
4x faster for deferred loading (see https://code.djangoproject.com/ticket/19501
for some performance numbers). Unfortunately this change is hard to do
with any kind of backwards compatibility period.

Here is the work-in-progress patch: 
https://github.com/akaariai/django/compare/defer_getattr.
Unfortunately I don't have time to work on this more until start of
June or so...

 - Anssi

-- 
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-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to