#31680: Preventing DeferredAttribute .__ get__ method unnecessary calls
-------------------------------------+-------------------------------------
     Reporter:  Sultan               |                    Owner:  nobody
         Type:                       |                   Status:  new
  Cleanup/optimization               |
    Component:  Database layer       |                  Version:  3.1
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  1                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Description changed by Sultan:

Old description:

> To retrieve a deferred model attributes, the __get__ method is called
> twice. This is because it uses the getattr() function, which in turn
> causes the __get__ method to be called again.
>

> {{{
>     def __get__(self, instance, cls=None):
>         """
>         Retrieve and caches the value from the datastore on the first
> lookup.
>         Return the cached value.
>         """
>         if instance is None:
>             return self
>         data = instance.__dict__
>         field_name = self.field.attname
>         if field_name not in data:
>             # Let's see if the field is part of the parent chain. If so
> we
>             # might be able to reuse the already loaded value. Refs
> #18343.
>             val = self._check_parent_chain(instance)
>             if val is None:
>                 instance.refresh_from_db(fields=[field_name])
>                 **val = getattr(instance, field_name)**
>             data[field_name] = val
>         return data[field_name]
> }}}
>

> To prevent this unnecessary call, we can simply extract the value from
> the instance dict (at that moment it already contains the searched
> value):
>

> {{{
>     def __get__(self, instance, cls=None):
>         """
>         Retrieve and caches the value from the datastore on the first
> lookup.
>         Return the cached value.
>         """
>         if instance is None:
>             return self
>         data = instance.__dict__
>         field_name = self.field.attname
>         if field_name not in data:
>             # Let's see if the field is part of the parent chain. If so
> we
>             # might be able to reuse the already loaded value. Refs
> #18343.
>             val = self._check_parent_chain(instance)
>             if val is None:
>                 instance.refresh_from_db(fields=[field_name])
>                 # Now the instance dict contains the reloaded data.
>                 # Using getattr() will do extra call to __get__ method.
>                 **val = data[field_name]**
>             data[field_name] = val
>         return data[field_name]
> }}}
>
> This reduces the number of method calls.

New description:

 To retrieve a deferred model attributes, the __get__ method is called
 twice. This is because it uses the getattr() function, which in turn
 causes the __get__ method to be called again.


 {{{
     def __get__(self, instance, cls=None):
         """
         Retrieve and caches the value from the datastore on the first
 lookup.
         Return the cached value.
         """
         if instance is None:
             return self
         data = instance.__dict__
         field_name = self.field.attname
         if field_name not in data:
             # Let's see if the field is part of the parent chain. If so we
             # might be able to reuse the already loaded value. Refs
 #18343.
             val = self._check_parent_chain(instance)
             if val is None:
                 instance.refresh_from_db(fields=[field_name])
                 **val = getattr(instance, field_name)**
             data[field_name] = val
         return data[field_name]
 }}}


 To prevent this unnecessary call, we can simply extract the value from the
 instance dict (at that moment it already contains the reloaded value):


 {{{
     def __get__(self, instance, cls=None):
         """
         Retrieve and caches the value from the datastore on the first
 lookup.
         Return the cached value.
         """
         if instance is None:
             return self
         data = instance.__dict__
         field_name = self.field.attname
         if field_name not in data:
             # Let's see if the field is part of the parent chain. If so we
             # might be able to reuse the already loaded value. Refs
 #18343.
             val = self._check_parent_chain(instance)
             if val is None:
                 instance.refresh_from_db(fields=[field_name])
                 # Now the instance dict contains the reloaded data.
                 # Using getattr() will do extra call to __get__ method.
                 **val = data[field_name]**
             data[field_name] = val
         return data[field_name]
 }}}

 This reduces the number of method calls.

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/31680#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.ffbe40c548b47fa374a89f0ccd4ef39f%40djangoproject.com.

Reply via email to