Fixed #31701 -- Made FileDescriptor subclass DeferredAttribute.
This commit is contained in:
parent
dd5aa8cb5f
commit
a93425a37f
|
@ -8,6 +8,7 @@ from django.core.files.images import ImageFile
|
||||||
from django.core.files.storage import Storage, default_storage
|
from django.core.files.storage import Storage, default_storage
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
from django.db.models.fields import Field
|
from django.db.models.fields import Field
|
||||||
|
from django.db.models.query_utils import DeferredAttribute
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -140,7 +141,7 @@ class FieldFile(File):
|
||||||
self.storage = self.field.storage
|
self.storage = self.field.storage
|
||||||
|
|
||||||
|
|
||||||
class FileDescriptor:
|
class FileDescriptor(DeferredAttribute):
|
||||||
"""
|
"""
|
||||||
The descriptor for the file attribute on the model instance. Return a
|
The descriptor for the file attribute on the model instance. Return a
|
||||||
FieldFile when accessed so you can write code like::
|
FieldFile when accessed so you can write code like::
|
||||||
|
@ -154,9 +155,6 @@ class FileDescriptor:
|
||||||
>>> with open('/path/to/hello.world') as f:
|
>>> with open('/path/to/hello.world') as f:
|
||||||
... instance.file = File(f)
|
... instance.file = File(f)
|
||||||
"""
|
"""
|
||||||
def __init__(self, field):
|
|
||||||
self.field = field
|
|
||||||
|
|
||||||
def __get__(self, instance, cls=None):
|
def __get__(self, instance, cls=None):
|
||||||
if instance is None:
|
if instance is None:
|
||||||
return self
|
return self
|
||||||
|
@ -173,9 +171,7 @@ class FileDescriptor:
|
||||||
|
|
||||||
# The instance dict contains whatever was originally assigned
|
# The instance dict contains whatever was originally assigned
|
||||||
# in __set__.
|
# in __set__.
|
||||||
if self.field.name not in instance.__dict__:
|
file = super().__get__(instance, cls)
|
||||||
instance.refresh_from_db(fields=[self.field.name])
|
|
||||||
file = instance.__dict__[self.field.name]
|
|
||||||
|
|
||||||
# If this value is a string (instance.file = "path/to/file") or None
|
# If this value is a string (instance.file = "path/to/file") or None
|
||||||
# then we simply wrap it with the appropriate attribute class according
|
# then we simply wrap it with the appropriate attribute class according
|
||||||
|
@ -186,7 +182,7 @@ class FileDescriptor:
|
||||||
# handle None.
|
# handle None.
|
||||||
if isinstance(file, str) or file is None:
|
if isinstance(file, str) or file is None:
|
||||||
attr = self.field.attr_class(instance, self.field, file)
|
attr = self.field.attr_class(instance, self.field, file)
|
||||||
instance.__dict__[self.field.name] = attr
|
instance.__dict__[self.field.attname] = attr
|
||||||
|
|
||||||
# Other types of files may be assigned as well, but they need to have
|
# Other types of files may be assigned as well, but they need to have
|
||||||
# the FieldFile interface added to them. Thus, we wrap any other type of
|
# the FieldFile interface added to them. Thus, we wrap any other type of
|
||||||
|
@ -196,7 +192,7 @@ class FileDescriptor:
|
||||||
file_copy = self.field.attr_class(instance, self.field, file.name)
|
file_copy = self.field.attr_class(instance, self.field, file.name)
|
||||||
file_copy.file = file
|
file_copy.file = file
|
||||||
file_copy._committed = False
|
file_copy._committed = False
|
||||||
instance.__dict__[self.field.name] = file_copy
|
instance.__dict__[self.field.attname] = file_copy
|
||||||
|
|
||||||
# Finally, because of the (some would say boneheaded) way pickle works,
|
# Finally, because of the (some would say boneheaded) way pickle works,
|
||||||
# the underlying FieldFile might not actually itself have an associated
|
# the underlying FieldFile might not actually itself have an associated
|
||||||
|
@ -211,10 +207,10 @@ class FileDescriptor:
|
||||||
file.instance = instance
|
file.instance = instance
|
||||||
|
|
||||||
# That was fun, wasn't it?
|
# That was fun, wasn't it?
|
||||||
return instance.__dict__[self.field.name]
|
return instance.__dict__[self.field.attname]
|
||||||
|
|
||||||
def __set__(self, instance, value):
|
def __set__(self, instance, value):
|
||||||
instance.__dict__[self.field.name] = value
|
instance.__dict__[self.field.attname] = value
|
||||||
|
|
||||||
|
|
||||||
class FileField(Field):
|
class FileField(Field):
|
||||||
|
@ -303,10 +299,6 @@ class FileField(Field):
|
||||||
file.save(file.name, file.file, save=False)
|
file.save(file.name, file.file, save=False)
|
||||||
return file
|
return file
|
||||||
|
|
||||||
def contribute_to_class(self, cls, name, **kwargs):
|
|
||||||
super().contribute_to_class(cls, name, **kwargs)
|
|
||||||
setattr(cls, self.name, self.descriptor_class(self))
|
|
||||||
|
|
||||||
def generate_filename(self, instance, filename):
|
def generate_filename(self, instance, filename):
|
||||||
"""
|
"""
|
||||||
Apply (if callable) or prepend (if a string) upload_to to the filename,
|
Apply (if callable) or prepend (if a string) upload_to to the filename,
|
||||||
|
@ -345,7 +337,7 @@ class ImageFileDescriptor(FileDescriptor):
|
||||||
assigning the width/height to the width_field/height_field, if appropriate.
|
assigning the width/height to the width_field/height_field, if appropriate.
|
||||||
"""
|
"""
|
||||||
def __set__(self, instance, value):
|
def __set__(self, instance, value):
|
||||||
previous_file = instance.__dict__.get(self.field.name)
|
previous_file = instance.__dict__.get(self.field.attname)
|
||||||
super().__set__(instance, value)
|
super().__set__(instance, value)
|
||||||
|
|
||||||
# To prevent recalculating image dimensions when we are instantiating
|
# To prevent recalculating image dimensions when we are instantiating
|
||||||
|
|
Loading…
Reference in New Issue