Refs #30657 -- Made DeferredAttribute.__init__() to take a field instance instead of a field name.
This commit is contained in:
parent
fc75694257
commit
93ffa81bc5
|
@ -14,10 +14,9 @@ class SpatialProxy(DeferredAttribute):
|
||||||
Initialize on the given Geometry or Raster class (not an instance)
|
Initialize on the given Geometry or Raster class (not an instance)
|
||||||
and the corresponding field.
|
and the corresponding field.
|
||||||
"""
|
"""
|
||||||
self._field = field
|
|
||||||
self._klass = klass
|
self._klass = klass
|
||||||
self._load_func = load_func or klass
|
self._load_func = load_func or klass
|
||||||
super().__init__(field.attname)
|
super().__init__(field)
|
||||||
|
|
||||||
def __get__(self, instance, cls=None):
|
def __get__(self, instance, cls=None):
|
||||||
"""
|
"""
|
||||||
|
@ -32,7 +31,7 @@ class SpatialProxy(DeferredAttribute):
|
||||||
|
|
||||||
# Getting the value of the field.
|
# Getting the value of the field.
|
||||||
try:
|
try:
|
||||||
geo_value = instance.__dict__[self._field.attname]
|
geo_value = instance.__dict__[self.field.attname]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
geo_value = super().__get__(instance, cls)
|
geo_value = super().__get__(instance, cls)
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ class SpatialProxy(DeferredAttribute):
|
||||||
# Otherwise, a geometry or raster object is built using the field's
|
# Otherwise, a geometry or raster object is built using the field's
|
||||||
# contents, and the model's corresponding attribute is set.
|
# contents, and the model's corresponding attribute is set.
|
||||||
geo_obj = self._load_func(geo_value)
|
geo_obj = self._load_func(geo_value)
|
||||||
setattr(instance, self._field.attname, geo_obj)
|
setattr(instance, self.field.attname, geo_obj)
|
||||||
return geo_obj
|
return geo_obj
|
||||||
|
|
||||||
def __set__(self, instance, value):
|
def __set__(self, instance, value):
|
||||||
|
@ -56,7 +55,7 @@ class SpatialProxy(DeferredAttribute):
|
||||||
To set rasters, use JSON or dict values.
|
To set rasters, use JSON or dict values.
|
||||||
"""
|
"""
|
||||||
# The geographic type of the field.
|
# The geographic type of the field.
|
||||||
gtype = self._field.geom_type
|
gtype = self.field.geom_type
|
||||||
|
|
||||||
if gtype == 'RASTER' and (value is None or isinstance(value, (str, dict, self._klass))):
|
if gtype == 'RASTER' and (value is None or isinstance(value, (str, dict, self._klass))):
|
||||||
# For raster fields, assure input is None or a string, dict, or
|
# For raster fields, assure input is None or a string, dict, or
|
||||||
|
@ -67,7 +66,7 @@ class SpatialProxy(DeferredAttribute):
|
||||||
# general GeometryField is used.
|
# general GeometryField is used.
|
||||||
if value.srid is None:
|
if value.srid is None:
|
||||||
# Assigning the field SRID if the geometry has no SRID.
|
# Assigning the field SRID if the geometry has no SRID.
|
||||||
value.srid = self._field.srid
|
value.srid = self.field.srid
|
||||||
elif value is None or isinstance(value, (str, memoryview)):
|
elif value is None or isinstance(value, (str, memoryview)):
|
||||||
# Set geometries with None, WKT, HEX, or WKB
|
# Set geometries with None, WKT, HEX, or WKB
|
||||||
pass
|
pass
|
||||||
|
@ -76,5 +75,5 @@ class SpatialProxy(DeferredAttribute):
|
||||||
instance.__class__.__name__, gtype, type(value)))
|
instance.__class__.__name__, gtype, type(value)))
|
||||||
|
|
||||||
# Setting the objects dictionary with the value, and returning.
|
# Setting the objects dictionary with the value, and returning.
|
||||||
instance.__dict__[self._field.attname] = value
|
instance.__dict__[self.field.attname] = value
|
||||||
return value
|
return value
|
||||||
|
|
|
@ -738,7 +738,7 @@ class Field(RegisterLookupMixin):
|
||||||
# if you have a classmethod and a field with the same name, then
|
# if you have a classmethod and a field with the same name, then
|
||||||
# such fields can't be deferred (we don't have a check for this).
|
# such fields can't be deferred (we don't have a check for this).
|
||||||
if not getattr(cls, self.attname, None):
|
if not getattr(cls, self.attname, None):
|
||||||
setattr(cls, self.attname, DeferredAttribute(self.attname))
|
setattr(cls, self.attname, DeferredAttribute(self))
|
||||||
if self.choices is not None:
|
if self.choices is not None:
|
||||||
setattr(cls, 'get_%s_display' % self.name,
|
setattr(cls, 'get_%s_display' % self.name,
|
||||||
partialmethod(cls._get_FIELD_display, field=self))
|
partialmethod(cls._get_FIELD_display, field=self))
|
||||||
|
|
|
@ -116,8 +116,8 @@ class DeferredAttribute:
|
||||||
A wrapper for a deferred-loading field. When the value is read from this
|
A wrapper for a deferred-loading field. When the value is read from this
|
||||||
object the first time, the query is executed.
|
object the first time, the query is executed.
|
||||||
"""
|
"""
|
||||||
def __init__(self, field_name):
|
def __init__(self, field):
|
||||||
self.field_name = field_name
|
self.field = field
|
||||||
|
|
||||||
def __get__(self, instance, cls=None):
|
def __get__(self, instance, cls=None):
|
||||||
"""
|
"""
|
||||||
|
@ -127,26 +127,26 @@ class DeferredAttribute:
|
||||||
if instance is None:
|
if instance is None:
|
||||||
return self
|
return self
|
||||||
data = instance.__dict__
|
data = instance.__dict__
|
||||||
if data.get(self.field_name, self) is self:
|
field_name = self.field.attname
|
||||||
|
if data.get(field_name, self) is self:
|
||||||
# Let's see if the field is part of the parent chain. If so we
|
# 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.
|
# might be able to reuse the already loaded value. Refs #18343.
|
||||||
val = self._check_parent_chain(instance, self.field_name)
|
val = self._check_parent_chain(instance)
|
||||||
if val is None:
|
if val is None:
|
||||||
instance.refresh_from_db(fields=[self.field_name])
|
instance.refresh_from_db(fields=[field_name])
|
||||||
val = getattr(instance, self.field_name)
|
val = getattr(instance, field_name)
|
||||||
data[self.field_name] = val
|
data[field_name] = val
|
||||||
return data[self.field_name]
|
return data[field_name]
|
||||||
|
|
||||||
def _check_parent_chain(self, instance, name):
|
def _check_parent_chain(self, instance):
|
||||||
"""
|
"""
|
||||||
Check if the field value can be fetched from a parent field already
|
Check if the field value can be fetched from a parent field already
|
||||||
loaded in the instance. This can be done if the to-be fetched
|
loaded in the instance. This can be done if the to-be fetched
|
||||||
field is a primary key field.
|
field is a primary key field.
|
||||||
"""
|
"""
|
||||||
opts = instance._meta
|
opts = instance._meta
|
||||||
f = opts.get_field(name)
|
link_field = opts.get_ancestor_link(self.field.model)
|
||||||
link_field = opts.get_ancestor_link(f.model)
|
if self.field.primary_key and self.field != link_field:
|
||||||
if f.primary_key and f != link_field:
|
|
||||||
return getattr(instance, link_field.attname)
|
return getattr(instance, link_field.attname)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue