用户尝试上传照片时出现FileNotFoundError

时间:2019-12-16 23:48:19

标签: python django

当用户尝试注册我的网站并上传照片时,我收到FileNotFoundError错误消息。错误消息如下:

[Errno 2] No such file or directory: '/tmp/<file_name>.upload.jpg'

<file_name>是随机文件名。

最近我收到了一些类似的消息,这些用户无法上传照片并完成注册(用户必须拥有个人资料照片才能成为Speedy Match的活跃成员)。你知道是什么问题吗?我正在将Django 2.1.15与Python 3.6.8配合使用。

我现在使用Chrome和Firefox进行了检查,并能够注册到我的网站并上传照片。注册网站的大多数用户都成功上传了照片。但是最近对某些特定用户失败了。

以下是一些代码:

def clean_photo(self):
    photo = self.files.get('photo')
    if (photo):
        speedy_match_accounts_validators.validate_photo_for_user(user=self.instance.user, photo=photo)
    else:
        photo = self.instance.user.photo
        speedy_match_accounts_validators.validate_photo_for_user(user=self.instance.user, photo=photo, test_new_photo=False)
    return self.cleaned_data

def save(self, commit=True):
    if (commit):
        if ('photo' in self.fields):
            if (self.files):
                user_image = Image(owner=self.instance.user, file=self.files['photo'])
                user_image.save()
                self.instance.user.photo = user_image
        for field_name in self.user_fields:
            if (field_name in self.fields):
                setattr(self.instance.user, field_name, self.cleaned_data[field_name])
        self.instance.user.save()
    super().save(commit=commit)

def validate_photo_for_user(user, photo, test_new_photo=True):
    validate_photo(photo=photo)
    if (test_new_photo):
        user._photo = user.photo
    photo_is_valid = False
    try:
        if (test_new_photo):
            user_image = Image(owner=user, file=photo)
            user_image.save()
            user.photo = user_image
        profile_picture_html = render_to_string(template_name="accounts/tests/profile_picture_test.html", context={"user": user})
        logger.debug('validate_photo_for_user::user={user}, profile_picture_html={profile_picture_html}'.format(
            user=user,
            profile_picture_html=profile_picture_html,
        ))
        if (not ('speedy-core/images/user.svg' in profile_picture_html)):
            photo_is_valid = True
    except:
        photo_is_valid = False
    if (test_new_photo):
        user.photo = user._photo
        try:
            user_image.delete()
        except:
            pass
    if (not (photo_is_valid)):
        raise ValidationError(_("You can't use this format for your profile picture. Only JPEG or PNG formats are accepted."))

可以在GitHub上看到网站的代码。

以下是我通过电子邮件收到的详细信息:

FileNotFoundError at /registration-step-2/
[Errno 2] No such file or directory: '/tmp/....upload.jpg' (I removed the file name)
Request Method: POST
Request URL: https://he.speedymatch.com/registration-step-2/
Django Version: 2.1.15
Exception Type: FileNotFoundError
Exception Value:
[Errno 2] No such file or directory: '/tmp/....upload.jpg' (I removed the file name)
Exception Location: .../site-packages/django/core/files/move.py in file_move_safe, line 56 (I removed the path)
Python Executable: /usr/bin/uwsgi-core
Python Version: 3.6.8

我也收到了很多变量的回溯,但是太个人化了,无法在此网站上分享。

回溯包含以下几行:

self.object = form.save()

user_image.save()

return super().save(*args, **kwargs)

return super().save(*args, **kwargs)

return super().save(*args, **kwargs)

force_update=force_update, update_fields=update_fields)

self._save_parents(cls, using, update_fields)

self._save_table(cls=parent, using=using, update_fields=update_fields)

for f in non_pks]

for f in non_pks]

file.save(file.name, file.file, save=False)

self.name = self.storage.save(name, content, max_length=self.field.max_length)

return self._save(name, content)

file_move_safe(content.temporary_file_path(), full_path)

with open(old_file_name, 'rb') as old_file:

2 个答案:

答案 0 :(得分:3)

仅当文件大小大于2.5 MB时,该错误才可重现:

# Maximum size, in bytes, of a request before it will be streamed to the
# file system instead of into memory.
FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440  # i.e. 2.5 MB

为防止错误,您可以执行以下操作之一:

  • 检查文件系统用户对/tmp目录的权限,并在可能的情况下授予访问权限。
  • FILE_UPLOAD_TEMP_DIR设置为文件系统用户可以在其中写入和读取的目录。如果Python的NamedTemporaryFile无法取消链接,则应定期清除此内容。

答案 1 :(得分:1)

设置中的这一行至少可以暂时解决此问题:

FILE_UPLOAD_MAX_MEMORY_SIZE = int(15 * 1024 * 1024)  # 15 MB

user_image.save()被调用两次-一次用于验证图片,然后再次将其保存为用户的个人资料图片(如果有效)。如果文件大小大于FILE_UPLOAD_MAX_MEMORY_SIZE字节(默认为2.5 MB),则会导致错误。一次调用user_image.save()将解决此问题。

我修复了代码,这是有效的代码。每个文件仅保存一次:

def clean_photo(self):
    photo = self.files.get('photo')
    if (photo):
        user_image = Image(owner=self.instance.user, file=photo)
        user_image.save()
        self.instance.user._new_photo = user_image
        speedy_match_accounts_validators.validate_photo_for_user(user=self.instance.user, photo=photo, test_new_photo=True)
    else:
        photo = self.instance.user.photo
        speedy_match_accounts_validators.validate_photo_for_user(user=self.instance.user, photo=photo, test_new_photo=False)
    return self.cleaned_data

def save(self, commit=True):
    if (commit):
        if ('photo' in self.fields):
            photo = self.files.get('photo')
            if (photo):
                self.instance.user.photo = self.instance.user._new_photo
        for field_name in self.user_fields:
            if (field_name in self.fields):
                setattr(self.instance.user, field_name, self.cleaned_data[field_name])
        self.instance.user.save()
    super().save(commit=commit)

def validate_photo_for_user(user, photo, test_new_photo):
    validate_photo(photo=photo)
    if (test_new_photo):
        user._photo = user.photo
    photo_is_valid = False
    try:
        if (test_new_photo):
            user.photo = user._new_photo
        profile_picture_html = render_to_string(template_name="accounts/tests/profile_picture_test.html", context={"user": user})
        logger.debug('validate_photo_for_user::user={user}, profile_picture_html={profile_picture_html}'.format(
            user=user,
            profile_picture_html=profile_picture_html,
        ))
        if (not ('speedy-core/images/user.svg' in profile_picture_html)):
            photo_is_valid = True
    except:
        photo_is_valid = False
    if (test_new_photo):
        user.photo = user._photo
    if (not (photo_is_valid)):
        raise ValidationError(_("You can't use this format for your profile picture. Only JPEG or PNG formats are accepted."))

使用此代码,我可以将FILE_UPLOAD_MAX_MEMORY_SIZE保留为默认值(2.5 MB)或任何值。目前,我将其设置为7.5 MB。