Подозрительная операция Django

У меня возникла проблема при попытке удалить загруженные изображения.

Ошибка в этих строках:

SuspiciousOperation: Attempted access to '/media/artists/12-stones/154339.jpg' denied.

После прочтения это выглядит так: ошибка возникает из-за того, что он ищет изображение в неправильном месте (обратите внимание, что сначала слэш,/media/не существует в файловой системе)

Мои MEDIA_ROOT и MEDIA_URL:

MEDIA_ROOT = '/home/tsoporan/site/media/'
MEDIA_URL = "/media/

Моим параметрам upload_to моей модели передается эта функция:

def get_artist_path(instance, filename):
  return os.path.join('artists', slugify(instance.name), filename)

Мои вопросы:

1) Как я могу исправить эту проблему для будущих загрузок?

2) Можно ли исправить пути моих текущих изображений без повторной загрузки?

С уважением, Titus

Ответ 1

Хорошо, что немного кода в коде показывает, что может быть более глубокое сообщение об ошибке, которое стало гомогенизированным на этом пути.

в django/core/files/storage.py, строка 210 (это в 1.1.1), мы имеем:

def path(self, name):
    try:
        path = safe_join(self.location, name)
    except ValueError:
        raise SuspiciousOperation("Attempted access to '%s' denied." % name)
    return smart_str(os.path.normpath(path))

Таким образом, ошибка должна выходить из safe_join().

В django/utils/_os.py мы имеем следующее. Обратите внимание на значение ValueError, которое он выбрасывает на третьей в последнюю строку:

===========================

def safe_join(base, *paths):
    """
    Joins one or more path components to the base path component intelligently.
    Returns a normalized, absolute version of the final path.

    The final path must be located inside of the base path component (otherwise
    a ValueError is raised).
    """
    # We need to use normcase to ensure we don't false-negative on case
    # insensitive operating systems (like Windows).
    base = force_unicode(base)
    paths = [force_unicode(p) for p in paths]
    final_path = normcase(abspathu(join(base, *paths)))
    base_path = normcase(abspathu(base))
    base_path_len = len(base_path)
    # Ensure final_path starts with base_path and that the next character after
    # the final path is os.sep (or nothing, in which case final_path must be
    # equal to base_path).
    if not final_path.startswith(base_path) \
       or final_path[base_path_len:base_path_len+1] not in ('', sep):
        raise ValueError('the joined path is located outside of the base path'
                         ' component')
    return final_path

==================

Hmmm, "Связанный путь расположен за пределами базового компонента пути". Теперь есть пара вызовов abspathu() (которые определены чуть выше этой подпрограммы и отличаются для NT, чем для других ОС). abspathu() преобразует все не-абсолютные пути в абсолютные, применяя к os.cwdu() текущий рабочий каталог.

Вопрос: У вас есть символическая ссылка в вашей медиа-директории? Другими словами, это не прямой дочерний элемент каталога проекта? Я не знаю, действительно ли это правильный вопрос, он просто выскочил из моей головы.

Вопрос: Каковы значения self.location и name, которые передаются в safe_join()?

Wild-ass-guess: is self.location empty?

Еще одна дикая задница: действительно ли MEDIA_ROOT изменился на /media/?

Если у вас установлена ​​ваша собственная копия Django (это не сложно сделать), попробуйте поместить некоторые инструкции печати в эти подпрограммы, а затем запустите ее как сервер разработки. Выход на печать перейдет на консоль.

Обновление: Хммм. Вы сказали "2". Значения для самораспространения и имени:/home/tsoporan/site/media и /media/albums/anthem -for-the-underdog/30103635.jpg "

Имеет ли смысл следующий путь?

"/home/tsoporan/site/media/media/albums/anthem-for-the-underdog"

Обратите внимание на... /media/media/... там.

Кроме того, какая ОС это? Django rev?

Ответ 2

Я получил эту ошибку, когда поставил ключевую косую черту в определении upload_to.

BAD

pic = models.ImageField(upload_to="/uploads/product_images/")

ХОРОШО

pic = models.ImageField(upload_to="uploads/product_images/")

Ответ 3

В качестве примечания для других эта проблема может быть вызвана, если у вас есть двойной "//" в статическом файловом ресурсе, который вы ищете.

{{ STATIC_URL }}/style.css # Causes the issue it should be
{{ STATIC_URL }}style.css

Ответ 4

Ах понял это, немного неловко, но оказалось, что ошибка была выше. Я подключал эти изображения с помощью script, и, перейдя через него, понял, что мои пути начинаются с /media/.

Теперь у меня около 4000 изображений с неправильными путями... есть ли способ как-то изменить пути для всех этих изображений? Или потребуется перезагрузка?

Спасибо всем, извинившись за мою ошибку.

Ответ 5

Вы действительно должны просто задать новый вопрос. Попробуйте следующее:

Напишите автономный django script, который выглядит примерно так:

from django.core.management import setup_environ
from mysite import settings
setup_environ(settings)
from django.db import transaction

from app.models import Album # or whatever your model name is

for a in Album.objects.all():
    # Do something to cleanup the filename.
    # NOTE! This will not move the files, just change the value in the field.
    a.filename = re.sub(r'^/media', '', a.filename)
    a.save()

transaction.commit_unless_managed() # flush all changes

Ответ 6

если вы хотите использовать другое местоположение, например /data/images/myfile/, вы должны установить MEDIA_ROOT в /data/images в файле настроек django settings.py.

Ответ 7

Я обнаружил, используя немые теги print, что некоторые медиа файлы имеют /media с префиксом в своих URL-адресах. Хотя опция хранения по умолчанию справляется с этим, возникает проблема, если вы используете S3BotoStorage из django-storages.

Поэтому я исправил его, переопределив _normalize_name (руководствуясь ответом @peter-rowell):

class MediaStorage(FixedUrlBotoStorage):
    location = settings.MEDIAFILES_LOCATION

    # Overriding function because some media files are stored with '/media' prefixed (which causes problems)
    def _normalize_name(self, name):
        if name.startswith('/media'):
            name = name.lstrip('/media')
        return super(MediaStorage, self)._normalize_name(name)

Ответ 8

Используйте SimpleUploadedFile если ваш временный файл не является частью папки MEDIA_ROOT. Это не выдаст ошибку SuspiciousOperation:

upload_file = SimpleUploadedFile(name=basename(out_file), content=open(out_file, 'rb').read())
object = YourModel.objects.create(file=upload_file)

Используйте File если ваш временный файл уже является частью MEDIA_ROOT. Это полезно, если вы хотите связать существующий файл Django с объектом.

object = YourModel.objects.create(file=File(open(file_path, 'rb')))

Ответ 10

Я тоже получил эту ошибку. Отладка через я обнаружил, что возникает следующее исключение.

SuspiciousOperation(u"Attempted access to '2015-03-19-08:29:51-2-f8945842891244629dfd0c0af4c72a9c.pdf' denied.",)

Кстати, я использую django-хранилища (v1.1.8) для хранения моих медиафайлов на S3 (используя бэкэнд S3boto). Я использую django 1.7.6.

Но если я переключусь на сохранение с именем файла с двоеточиями (:), похоже, это сработает. Я еще не понял, что является основной причиной. Просто опубликуйте это, если это поможет кому-то другому. По-видимому, django или django-хранилища не любят имена файлов с двоеточиями.