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.