def contribute_to_class(self, cls, name, private_only=False, virtual_only=NOT_PROVIDED):
"""
Register the field with the model class it belongs to.
If private_only is True, a separate instance of this field will be
created for every subclass of cls, even if cls is not an abstract
model.
"""
if virtual_only is not NOT_PROVIDED:
warnings.warn(
"The `virtual_only` argument of Field.contribute_to_class() "
"has been renamed to `private_only`.",
RemovedInDjango20Warning, stacklevel=2
)
private_only = virtual_only
self.set_attributes_from_name(name)
self.model = cls
if private_only:
cls._meta.add_field(self, private=True)
else:
cls._meta.add_field(self)
if self.column:
# Don't override classmethods with the descriptor. This means that
# 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).
if not getattr(cls, self.attname, None):
setattr(cls, self.attname, DeferredAttribute(self.attname, cls))
if self.choices:
setattr(cls, 'get_%s_display' % self.name,
curry(cls._get_FIELD_display, field=self))
python类DeferredAttribute()的实例源码
def update_mptt_cached_fields(self, instance):
"""
Caches (in an instance._mptt_cached_fields dict) the original values of:
- parent pk
- fields specified in order_insertion_by
These are used in save() to determine if the relevant fields have changed,
so that the MPTT fields need to be updated.
"""
instance._mptt_cached_fields = {}
field_names = set((self.parent_attr,))
if self.order_insertion_by:
for f in self.order_insertion_by:
if f[0] == '-':
f = f[1:]
field_names.add(f)
deferred_fields = instance.get_deferred_fields()
for field_name in field_names:
if deferred_fields:
field = instance._meta.get_field(field_name)
if field.attname in deferred_fields \
and field.attname not in instance.__dict__:
# deferred attribute (i.e. via .only() or .defer())
# It'd be silly to cache this (that'd do a database query)
# Instead, we mark it as a deferred attribute here, then
# assume it hasn't changed during save(), unless it's no
# longer deferred.
instance._mptt_cached_fields[field_name] = DeferredAttribute
continue
instance._mptt_cached_fields[field_name] = self.get_raw_field_value(
instance, field_name)
def contribute_to_class(self, cls, name, private_only=False, virtual_only=NOT_PROVIDED):
"""
Register the field with the model class it belongs to.
If private_only is True, a separate instance of this field will be
created for every subclass of cls, even if cls is not an abstract
model.
"""
if virtual_only is not NOT_PROVIDED:
warnings.warn(
"The `virtual_only` argument of Field.contribute_to_class() "
"has been renamed to `private_only`.",
RemovedInDjango20Warning, stacklevel=2
)
private_only = virtual_only
self.set_attributes_from_name(name)
self.model = cls
if private_only:
cls._meta.add_field(self, private=True)
else:
cls._meta.add_field(self)
if self.column:
# Don't override classmethods with the descriptor. This means that
# 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).
if not getattr(cls, self.attname, None):
setattr(cls, self.attname, DeferredAttribute(self.attname, cls))
if self.choices:
setattr(cls, 'get_%s_display' % self.name,
curry(cls._get_FIELD_display, field=self))
def contribute_to_class(self, cls, name, private_only=False, virtual_only=NOT_PROVIDED):
"""
Register the field with the model class it belongs to.
If private_only is True, a separate instance of this field will be
created for every subclass of cls, even if cls is not an abstract
model.
"""
if virtual_only is not NOT_PROVIDED:
warnings.warn(
"The `virtual_only` argument of Field.contribute_to_class() "
"has been renamed to `private_only`.",
RemovedInDjango20Warning, stacklevel=2
)
private_only = virtual_only
self.set_attributes_from_name(name)
self.model = cls
if private_only:
cls._meta.add_field(self, private=True)
else:
cls._meta.add_field(self)
if self.column:
# Don't override classmethods with the descriptor. This means that
# 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).
if not getattr(cls, self.attname, None):
setattr(cls, self.attname, DeferredAttribute(self.attname, cls))
if self.choices:
setattr(cls, 'get_%s_display' % self.name,
curry(cls._get_FIELD_display, field=self))
def init_deferred_fields(self):
self.instance._deferred_fields = set()
if hasattr(self.instance, '_deferred') and not self.instance._deferred:
return
class DeferredAttributeTracker(DescriptorMixin, DeferredAttribute):
tracker_instance = self
class FileDescriptorTracker(DescriptorMixin, FileDescriptor):
tracker_instance = self
def _get_field_name(self):
return self.field.name
if django.VERSION >= (1, 8):
self.instance._deferred_fields = self.instance.get_deferred_fields()
for field in self.instance._deferred_fields:
if django.VERSION >= (1, 10):
field_obj = getattr(self.instance.__class__, field)
else:
field_obj = self.instance.__class__.__dict__.get(field)
if isinstance(field_obj, FileDescriptor):
field_tracker = FileDescriptorTracker(field_obj.field)
setattr(self.instance.__class__, field, field_tracker)
else:
field_tracker = DeferredAttributeTracker(
field_obj.field_name, None)
setattr(self.instance.__class__, field, field_tracker)
else:
for field in self.fields:
field_obj = self.instance.__class__.__dict__.get(field)
if isinstance(field_obj, DeferredAttribute):
self.instance._deferred_fields.add(field)
# Django 1.4
if django.VERSION >= (1, 5):
model = None
else:
model = field_obj.model_ref()
field_tracker = DeferredAttributeTracker(
field_obj.field_name, model)
setattr(self.instance.__class__, field, field_tracker)