def __get__(self, obj, cls=None): if obj is None: return self if self.name in obj.get_deferred_fields(): # This queries the database, and sets the value on the instance. if django.VERSION < (2, 1): DeferredAttribute(field_name=self.name, model=cls).__get__(obj, cls) else: DeferredAttribute(field_name=self.name).__get__(obj, cls) return str(obj.__dict__[self.name])
def __get__(self, obj, cls=None): if obj is None: return self if self.name in obj.get_deferred_fields(): # This queries the database, and sets the value on the instance. if django.VERSION < (3, 0): DeferredAttribute(field_name=self.name).__get__(obj, cls) else: # Since Django 3.0, DeferredAttribute wants a field argument. fields_map = {f.name: f for f in cls._meta.fields} field = fields_map[self.name] DeferredAttribute(field=field).__get__(obj, cls) return str(obj.__dict__[self.name])
def deferred_class_factory(model, attrs): """ Returns a class object that is a copy of "model" with the specified "attrs" being replaced with DeferredAttribute objects. The "pk_value" ties the deferred attributes to a particular instance of the model. """ class Meta: pass setattr(Meta, "proxy", True) setattr(Meta, "app_label", model._meta.app_label) class RenderMeta: pass setattr(RenderMeta, "index", model._render_meta.index) setattr(RenderMeta, "total", model._render_meta.total) setattr(RenderMeta, "text_enabled", model._render_meta.text_enabled) # The app_cache wants a unique name for each model, otherwise the new class # won't be created (we get an old one back). Therefore, we generate the # name using the passed in attrs. It's OK to reuse an old case if the attrs # are identical. name = "%s_Deferred_%s" % (model.__name__, '_'.join(sorted(list(attrs)))) overrides = dict([(attr, DeferredAttribute(attr, model)) for attr in attrs]) overrides["Meta"] = RenderMeta overrides["RenderMeta"] = RenderMeta overrides["__module__"] = model.__module__ overrides["_deferred"] = True return type(name, (model, ), overrides)
def test_model_fields(self): lines = [] simple_model_path = 'sphinxcontrib_django.tests.test_docstrings.SimpleModel' if django.VERSION < (3, 0): obj = DeferredAttribute(field_name='dummy_field', model=simple_model_path) else: model = import_string(simple_model_path) obj = DeferredAttribute(field=model._meta.get_field('dummy_field')) docstrings._improve_attribute_docs(obj, '{}.dummy_field'.format(simple_model_path), lines) self.assertEqual( lines, [ "**Model field:** dummy field", ], )
def get_state(self, instance): # The state field may be deferred. We delegate the logic of figuring # this out and loading the deferred field on-demand to Django's # built-in DeferredAttribute class. DeferredAttribute's instantiation # signature changed over time, so we need to check Django version # before proceeding to call DeferredAttribute. An alternative to this # would be copying the latest implementation of DeferredAttribute to # django_fsm, but this comes with the added responsibility of keeping # the copied code up to date. if django.VERSION[:3] >= (3, 0, 0): return DeferredAttribute(self).__get__(instance) elif django.VERSION[:3] >= (2, 1, 0): return DeferredAttribute(self.name).__get__(instance) elif django.VERSION[:3] >= (1, 10, 0): return DeferredAttribute(self.name, model=None).__get__(instance) else: # The field was either not deferred (in which case we can return it # right away) or ir was, but we are running on an unknown version # of Django and we do not know the appropriate DeferredAttribute # interface, and accessing the field will raise KeyError. return instance.__dict__[self.name]
def __get__(self, instance, cls=None): """ Return list of MultipleFieldFile at all times. """ if instance is None: return self # nocv instance.__dict__[self.field.attname] = [ self.get_file(file, instance) for file in DeferredAttribute.__get__(self, instance, cls) or [] ] return instance.__dict__[self.field.attname]
def __getattribute__(cls, key): if int(DJANGO_VERSION[0]) == 1 and int(DJANGO_VERSION[1]) < 10: try: field_pointer = super(DataBase, cls).__getattribute__(key) except AttributeError: if '_meta' in vars(cls) and \ key in (field.name for field in cls._meta.fields): field_pointer = DeferredAttribute(key, None) else: raise else: field_pointer = super(DataBase, cls).__getattribute__(key) if field_pointer is not None and \ isinstance(field_pointer, (DeferredAttribute, ForwardManyToOneDescriptor)): return DataPointer(field_ref=field_pointer) return field_pointer