试图理解 Django 源代码和缺少参数 TypeError 的原因
Trying to understand Django source code and cause of missing argument TypeError
A screenshot (portrait view) of my IDE and Traceback shows all the code pasteed here, 如果你有垂直显示器,可能更容易阅读。
上下文:尝试使用 S3BotoStorage 将图像从 URL 保存到托管在 EC2 上的 Django ImageField
以及 S3 上的文件。我很困惑,因为所有这些都表明 Django 仍然将其视为本地存储,而它应该是 S3。
似乎导致错误的相关行:
def get_filename(self, filename):
return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
def get_valid_name(self, name):
"""
Returns a filename, based on the provided filename, that's suitable for
use in the target storage system.
"""
return get_valid_filename(name)
类型错误异常:get_valid_name() missing 1 required positional argument: 'name'
在 get_valid_name
发生错误之前的最后一个局部变量 Tracback:
filename 'testimagefilename'
self <django.db.models.fields.files.ImageField: image>
(只有这两个水平分隔线里面的东西是我的,其余的是Django 1.9的)
image.image.save('testimagefilename', File(temp), save=True)
当时来自 Traceback 的本地变量(不确定 image
上的 ValueError
,我认为这是因为它尚未创建):
File <class 'django.core.files.base.File'>
image Error in formatting: ValueError: The 'image' attribute has no file associated with it.
requests <module 'requests' from '/usr/local/lib/python3.4/site-packages/requests/__init__.py'>
Image <class 'mcmaster.models.Image'>
NamedTemporaryFile <function NamedTemporaryFile at 0x7fb0e1bb0510>
temp <tempfile._TemporaryFileWrapper object at 0x7fb0dd241ef0>
Django源码相关片段:
files.py
def save(self, name, content, save=True):
name = self.field.generate_filename(self.instance, name)
if func_supports_parameter(self.storage.save, 'max_length'):
self.name = self.storage.save(name, content, max_length=self.field.max_length)
else:
warnings.warn(
'Backwards compatibility for storage backends without '
'support for the `max_length` argument in '
'Storage.save() will be removed in Django 1.10.',
RemovedInDjango110Warning, stacklevel=2
)
self.name = self.storage.save(name, content)
setattr(self.instance, self.field.name, self.name)
# Update the filesize cache
self._size = content.size
self._committed = True
# Save the object because it has changed, unless save is False
if save:
self.instance.save()
save.alters_data = True
def get_directory_name(self):
return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to))))
def get_filename(self, filename):
return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
def generate_filename(self, instance, filename):
# If upload_to is a callable, make sure that the path it returns is
# passed through get_valid_name() of the underlying storage.
if callable(self.upload_to):
directory_name, filename = os.path.split(self.upload_to(instance, filename))
filename = self.storage.get_valid_name(filename)
return os.path.normpath(os.path.join(directory_name, filename))
return os.path.join(self.get_directory_name(), self.get_filename(filename))
storage.py
def get_valid_name(self, name):
"""
Returns a filename, based on the provided filename, that's suitable for
use in the target storage system.
"""
return get_valid_filename(name)
text.py
def get_valid_filename(s):
"""
Returns the given string converted to a string that can be used for a clean
filename. Specifically, leading and trailing spaces are removed; other
spaces are converted to underscores; and anything that is not a unicode
alphanumeric, dash, underscore, or dot, is removed.
>>> get_valid_filename("john's portrait in 2004.jpg")
'johns_portrait_in_2004.jpg'
"""
s = force_text(s).strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w.]', '', s)
get_valid_filename = allow_lazy(get_valid_filename, six.text_type)
我猜你没有实例化存储 class。你如何设置 Django 以使用自定义存储?如果您在 models.py
中执行此操作
image = models.ImageField(storage=MyStorage)
它会完全按照您的描述失败。应该是
image = models.ImageField(storage=MyStorage())
A screenshot (portrait view) of my IDE and Traceback shows all the code pasteed here, 如果你有垂直显示器,可能更容易阅读。
上下文:尝试使用 S3BotoStorage 将图像从 URL 保存到托管在 EC2 上的 Django ImageField
以及 S3 上的文件。我很困惑,因为所有这些都表明 Django 仍然将其视为本地存储,而它应该是 S3。
似乎导致错误的相关行:
def get_filename(self, filename):
return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
def get_valid_name(self, name):
"""
Returns a filename, based on the provided filename, that's suitable for
use in the target storage system.
"""
return get_valid_filename(name)
类型错误异常:get_valid_name() missing 1 required positional argument: 'name'
在 get_valid_name
发生错误之前的最后一个局部变量 Tracback:
filename 'testimagefilename'
self <django.db.models.fields.files.ImageField: image>
(只有这两个水平分隔线里面的东西是我的,其余的是Django 1.9的)
image.image.save('testimagefilename', File(temp), save=True)
当时来自 Traceback 的本地变量(不确定 image
上的 ValueError
,我认为这是因为它尚未创建):
File <class 'django.core.files.base.File'>
image Error in formatting: ValueError: The 'image' attribute has no file associated with it.
requests <module 'requests' from '/usr/local/lib/python3.4/site-packages/requests/__init__.py'>
Image <class 'mcmaster.models.Image'>
NamedTemporaryFile <function NamedTemporaryFile at 0x7fb0e1bb0510>
temp <tempfile._TemporaryFileWrapper object at 0x7fb0dd241ef0>
Django源码相关片段:
files.py
def save(self, name, content, save=True):
name = self.field.generate_filename(self.instance, name)
if func_supports_parameter(self.storage.save, 'max_length'):
self.name = self.storage.save(name, content, max_length=self.field.max_length)
else:
warnings.warn(
'Backwards compatibility for storage backends without '
'support for the `max_length` argument in '
'Storage.save() will be removed in Django 1.10.',
RemovedInDjango110Warning, stacklevel=2
)
self.name = self.storage.save(name, content)
setattr(self.instance, self.field.name, self.name)
# Update the filesize cache
self._size = content.size
self._committed = True
# Save the object because it has changed, unless save is False
if save:
self.instance.save()
save.alters_data = True
def get_directory_name(self):
return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to))))
def get_filename(self, filename):
return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
def generate_filename(self, instance, filename):
# If upload_to is a callable, make sure that the path it returns is
# passed through get_valid_name() of the underlying storage.
if callable(self.upload_to):
directory_name, filename = os.path.split(self.upload_to(instance, filename))
filename = self.storage.get_valid_name(filename)
return os.path.normpath(os.path.join(directory_name, filename))
return os.path.join(self.get_directory_name(), self.get_filename(filename))
storage.py
def get_valid_name(self, name):
"""
Returns a filename, based on the provided filename, that's suitable for
use in the target storage system.
"""
return get_valid_filename(name)
text.py
def get_valid_filename(s):
"""
Returns the given string converted to a string that can be used for a clean
filename. Specifically, leading and trailing spaces are removed; other
spaces are converted to underscores; and anything that is not a unicode
alphanumeric, dash, underscore, or dot, is removed.
>>> get_valid_filename("john's portrait in 2004.jpg")
'johns_portrait_in_2004.jpg'
"""
s = force_text(s).strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w.]', '', s)
get_valid_filename = allow_lazy(get_valid_filename, six.text_type)
我猜你没有实例化存储 class。你如何设置 Django 以使用自定义存储?如果您在 models.py
中执行此操作image = models.ImageField(storage=MyStorage)
它会完全按照您的描述失败。应该是
image = models.ImageField(storage=MyStorage())