Ticket #3982: lazy_attribute.diff

File lazy_attribute.diff, 2.1 KB (added by Marty Alchin <gulopine@…>, 8 years ago)

An attempt at generic lazily-instantiated attributes

  • django/db/models/fields/__init__.py

     
    357357        "Returns the value of this field in the given model instance."
    358358        return getattr(obj, self.attname)
    359359
     360    def lazy_attribute(self, cls, creator=None, init=None):
     361        return AttributeProxy(self, cls, creator, init)
     362
     363class AttributeProxy(object):
     364    def __init__(self, field, cls, creator=None, init=None):
     365        self.field, self.cls = field, cls
     366        self.creator = creator or self.cls
     367        self.init = init or (lambda x: None)
     368
     369    def create(self, value):
     370        # Creates the attribute and makes sure it's a valid type
     371        value = self.creator(value)
     372        assert isinstance(value, self.cls), \
     373            "'%s.%s' did not return an object of type '%s'" % (
     374                self.field.model.object_name,
     375                self.field.attname,
     376                self.cls.__name__,
     377            )
     378        return value
     379       
     380    def __get__(self, obj, type=None):
     381        value = obj.__dict__[self.field.attname]
     382        if not getattr(obj, self.field.get_cache_name()):
     383            setattr(obj, self.field.attname, value)
     384        return obj.__dict__[self.field.attname]
     385
     386    def __set__(self, obj, value):
     387        if hasattr(obj, self.field.get_cache_name()):
     388            setattr(obj, self.field.get_cache_name(), False)
     389            if value is not None:
     390                if not isinstance(value, self.cls):
     391                    value = self.create(value)
     392                if not getattr(obj, self.field.get_cache_name()):
     393                    self.init(value)
     394                    setattr(obj, self.field.get_cache_name(), True)
     395        else:
     396            # This cache indicates whether the attribute has been instantiated
     397            setattr(obj, self.field.get_cache_name(), False)
     398        obj.__dict__[self.field.attname] = value
     399
    360400class AutoField(Field):
    361401    empty_strings_allowed = False
    362402    def __init__(self, *args, **kwargs):
Back to Top