Opened 4 years ago

Last modified 4 years ago

#31680 closed Cleanup/optimization

Preventing DeferredAttribute .__ get__ method unnecessary calls — at Initial Version

Reported by: Sultan Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

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.

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top