Everything you wanted to know
about the Django framework

Добавление хранилища Amazon S3 в проект Джанго

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

Зависимости

Вам нужно будет установить две библиотеки Python:

  • boto3
  • django-storages

Библиотека boto3 — это открытый клиент API для доступа к ресурсам Amazon Web Services (AWS), таким как Amazon S3. Это официальный дистрибутив, поддерживаемый Amazon.

django-storages — это библиотека с открытым исходным кодом для управления бэкэндами хранилищ, такими как Dropbox, OneDrive и Amazon S3. Это очень удобно, поскольку в него встроен API-интерфейс хранилища Django. Другими словами, это облегчит вам жизнь, поскольку не изменит кардинально то, как вы взаимодействуете со статическими или медиаресурсами. Нам нужно будет только добавить несколько параметров конфигурации, и библиотека сделает всю тяжелую работу за нас.

Настройка Amazon S3

Прежде чем мы перейдем к Django, давайте настроим S3. Нам нужно будет создать пользователя, который будет иметь доступ к управлению нашими ресурсами S3.

Войдите на веб-страницу AWS, найдите IAM в списке служб, он указан в разделе «Security, Identity & Compliance (Безопасность, идентификация и соответствие)»:

Перейдите на вкладку «Пользователи» и нажмите кнопку «Добавить пользователя»:

Добавьте имя пользователя и выберите опцию программного доступа:

Нажмите Далее, чтобы перейти к разрешениям. На этом этапе нам нужно создать новую группу с правами доступа S3 и добавить в нее нового пользователя. Следуйте указаниям мастера и нажмите кнопку «Создать группу»:

Определите имя для группы и найдите встроенную политику AmazonS3FullAccess:

Нажмите в группе «Создать», чтобы завершить процесс создания группы, на следующем экране, недавно созданная группа будет отображаться выбранной, сохраните ее и, наконец, нажмите кнопку «Далее: обзор»:

Просмотрите информацию, если все правильно, перейдите к созданию нового пользователя. Далее вы должны увидеть эту информацию:

Запишите всю информацию: пользователь, идентификатор ключа доступа и секретный ключ доступа. Сохраните их на потом.

Нажмите на кнопку Закрыть, и давайте продолжим. Теперь пришло время создать нашу первую «корзину».

Корзина (bucket) — это то, что мы называем контейнером хранения в S3. Мы можем работать с несколькими сегментами в рамках одного проекта Django. Но, по большей части, вам понадобится только одна корзина на сайт.

Нажмите в меню «Сервисы» и найдите S3. Он расположен под хранилищем. Если вы видите экран ниже, вы находитесь в правильном месте.

Нажмите на + Создать корзину, чтобы начать поток. Установите DNS-совместимое имя для вашей корзины. Оно будет использоваться для идентификации ваших активов. В моем случае я выбираю sibtc-static. Таким образом, путь к моим ресурсам будет примерно таким: https://sibtc-static.s3.amazonaws.com/static/.

Оставьте оставшиеся настройки без изменений, перейдите к следующим шагам, просто используя значения по умолчанию, и, наконец, нажмите кнопку «Создать корзину». Далее вы должны увидеть экран ниже:

Давайте оставим это так и начнем работать на стороне Джанго.

Установка

Самый простой способ - установить библиотеки с помощью pip:

pip install boto3
pip install django-storages

Теперь добавьте storages к вашему INSTALLED_APPS внутри модуля settings.py:

settings.py

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'storages',
]

Работа только со статическими активами

Это простейший вариант использования. Он работает "из коробки" с минимальной конфигурацией. Вся конфигурация ниже идет внутри модуля settings.py:

settings.py

AWS_ACCESS_KEY_ID = 'AKIAIT2Z5TDYPX3ARJBA'
AWS_SECRET_ACCESS_KEY = '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'
AWS_STORAGE_BUCKET_NAME = 'sibtc-static'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'mysite/static'),
]
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

Обратите внимание, что у нас есть конфиденциальная информация, такая как AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY. Не следует помещать его непосредственно в файл settings.py или фиксировать в общедоступном хранилище. Вместо этого используйте переменные окружения или используйте библиотеку Python Decouple.

Чтобы проиллюстрировать этот пример использования, я создал минимальный проект Django:

mysite/
 |-- mysite/
 |    |-- static/
 |    |    |-- css/
 |    |    |    +-- app.css
 |    |    +-- img/
 |    |         +-- thumbs-up.png
 |    |-- templates/
 |    |    +-- home.html
 |    |-- __init__.py
 |    |-- settings.py
 |    |-- urls.py
 |    +-- wsgi.py
 +-- manage.py

Как видите, обработка статических файлов должна проходить без проблем:

home.html

{% load static %}<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>S3 Example Static Only</title>
  <link rel="stylesheet" type="text/css" href="{% static 'css/app.css' %}">
</head>
<body>
  <header>
    <h1>S3 Example Static Only</h1>
  </header>
  <main>
    <img src="{% static 'img/thumbs-up.png' %}">
    <h2>It's working!</h2>
  </main>
  <footer>
    <a href="https://simpleisbetterthancomplex.com">www.SimpleIsBetterThanComplex.com</a>
  </footer>
</body>
</html>

Даже если мы используем нашу локальную машину, нам нужно будет выполнить команду collectstatic, так как наш код будет ссылаться на удаленное местоположение:

python manage.py collectstatic

Вы заметите, что процесс копирования займет больше времени, чем обычно. Это ожидаемо. Я удалил Django Admin из INSTALLED_APPS, чтобы пример стал чище. Но если вы попробуете это локально, вы увидите множество файлов, скопированных в вашу корзину S3.

Если мы проверим на веб-сайте AWS, мы увидим наши статические активы там:

И наконец, результат:

Как видите, серверная часть хранилища старается перевести тег шаблона {% static 'img / thumbs-up.png'%} в https://sibtc-static.s3.amazonaws.com/static/img/thumbs- up.png и загрузить его из корзины S3.

В следующем примере вы узнаете, как работать со статическими и медиа-активами.

Работа со статическими и медиаресурсами

Для этого примера я создал новую корзину с именем sibtc-assets.

Конфигурация settings.py будет очень похожа. За исключением того, что мы расширим storages.backends.s3boto3.S3Boto3Storage, добавив несколько пользовательских параметров, чтобы иметь возможность хранить загруженные пользователем файлы, то есть медиаресурсы, в другом месте, а также указывать S3 не переопределять файлы с помощью одно и то же имя

Обычно мне нравится создавать файл storage_backends.py в том же каталоге, что и мой settings.py, и вы можете определить новый бэкэнд хранилища следующим образом:

storage_backends.py

from storages.backends.s3boto3 import S3Boto3Storage

class MediaStorage(S3Boto3Storage):
    location = 'media'
    file_overwrite = False

Теперь в файле settings.py нам нужен новый бэкэнд для опции DEFAULT_FILE_STORAGE:

settings.py

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'mysite/static'),
]

AWS_ACCESS_KEY_ID = 'AKIAIT2Z5TDYPX3ARJBA'
AWS_SECRET_ACCESS_KEY = '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'
AWS_STORAGE_BUCKET_NAME = 'sibtc-assets'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME

AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}

AWS_LOCATION = 'static'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATIC_URL = "https://%s/%s/" % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)

DEFAULT_FILE_STORAGE = 'mysite.storage_backends.MediaStorage'  # <-- here is where we reference it

Для иллюстрации загрузки файла я создал приложение с именем core и определил следующую модель:

models.py

from django.db import models

class Document(models.Model):
    uploaded_at = models.DateTimeField(auto_now_add=True)
    upload = models.FileField()

Тогда вот как выглядит моё представление:

views.py

from django.contrib.auth.decorators import login_required
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy

from .models import Document


class DocumentCreateView(CreateView):
    model = Document
    fields = ['upload', ]
    success_url = reverse_lazy('home')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        documents = Document.objects.all()
        context['documents'] = documents
        return context

Шаблон document_form.html:

<form method="post" enctype="multipart/form-data">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Submit</button>
</form>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Uploaded at</th>
      <th>Size</th>
    </tr>
  </thead>
  <tbody>
    {% for document in documents %}
      <tr>
        <td><a href="{{ document.upload.url }}" target="_blank">{{ document.upload.name }}</a></td>
        <td>{{ document.uploaded_at }}</td>
        <td>{{ document.upload.size|filesizeformat }}</td>
      </tr>
    {% empty %}
      <tr>
        <td colspan="3">No data.</td>
      </tr>
    {% endfor %}
  </tbody>
</table>

Как вы можете видеть, я использую только встроенные ресурсы Django в шаблоне. Вот как выглядит этот шаблон:

Я не буду вдаваться в подробности о загрузке файлов, вы можете прочитать подробное руководство здесь в блоге (см. соответствующие ссылки в конце этой статьи для получения дополнительной информации).

Теперь тестируем загруженные пользователем файлы:

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

Затем, если мы нажмем на ссылку, которая является обычной {{ document.upload.url }}, управляемой Django, она отобразит изображение из корзины S3:

Теперь, если мы проверим нашу корзину, то увидим, что есть статический и медиа каталог:

Смешивание публичных активов и частных активов

Используя почти те же понятия, вы определяете некоторые ресурсы, которые будут храниться в хранилище S3 в частном порядке. Смотрите конфигурацию ниже:

storage_backends.py

from django.conf import settings
from storages.backends.s3boto3 import S3Boto3Storage

class StaticStorage(S3Boto3Storage):
    location = settings.AWS_STATIC_LOCATION

class PublicMediaStorage(S3Boto3Storage):
    location = settings.AWS_PUBLIC_MEDIA_LOCATION
    file_overwrite = False

class PrivateMediaStorage(S3Boto3Storage):
    location = settings.AWS_PRIVATE_MEDIA_LOCATION
    default_acl = 'private'
    file_overwrite = False
    custom_domain = False

settings.py

AWS_ACCESS_KEY_ID = 'AKIAIT2Z5TDYPX3ARJBA'
AWS_SECRET_ACCESS_KEY = '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'
AWS_STORAGE_BUCKET_NAME = 'sibtc-assets'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME

AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}

AWS_STATIC_LOCATION = 'static'
STATICFILES_STORAGE = 'mysite.storage_backends.StaticStorage'
STATIC_URL = "https://%s/%s/" % (AWS_S3_CUSTOM_DOMAIN, AWS_STATIC_LOCATION)

AWS_PUBLIC_MEDIA_LOCATION = 'media/public'
DEFAULT_FILE_STORAGE = 'mysite.storage_backends.PublicMediaStorage'

AWS_PRIVATE_MEDIA_LOCATION = 'media/private'
PRIVATE_FILE_STORAGE = 'mysite.storage_backends.PrivateMediaStorage'

Затем мы можем определить этот новый PrivateMediaStorage непосредственно в модели:

models.py

from django.db import models
from django.conf import settings
from django.contrib.auth.models import User

from mysite.storage_backends import PrivateMediaStorage


class Document(models.Model):
    uploaded_at = models.DateTimeField(auto_now_add=True)
    upload = models.FileField()


class PrivateDocument(models.Model):
    uploaded_at = models.DateTimeField(auto_now_add=True)
    upload = models.FileField(storage=PrivateMediaStorage())
    user = models.ForeignKey(User, related_name='documents')

После загрузки личного файла, если вы попытаетесь получить URL-адрес содержимого, API сгенерирует длинный URL-адрес, срок действия которого истекает через несколько минут.:

Если вы попытаетесь получить к нему доступ напрямую, без параметров, вы получите сообщение об ошибке от AWS:

Выводы

Я надеюсь, что это руководство помогло прояснить некоторые концепции Amazon S3 и помогло вам, по крайней мере, начать работу. Не бойтесь копаться в официальной документации как из boto3, так и из библиотеки django-storages.

 

Источник-оригинал: https://simpleisbetterthancomplex.com/tutorial/2017/08/01/how-to-setup-amazon-s3-in-a-django-project.html

Поделитесь с другими:

Представления-классы
(Class-Based Views)

Детальное описание и структура классов Django.

Выпуск Django 3.0

Команда Django рада объявить о выпуске Django 3.0: движение к тому, чтобы сделать Django полностью асинхронным, предоставляя поддержку для работы в качестве приложения ASGI, теперь официально поддерживает MariaDB 10.1 и выше, а также много других новых функций и возможностей.

Выпущены релизы безопасности Django: 2.2.8 и 2.1.15

В соответствии с политикой безопасности, команда Django выпускает Django 2.2.8 и Django 2.1.15. Этот выпуск решает проблему безопасности, подробно описанную ниже. Мы призываем всех пользователей Django обновиться как можно скорее.

Путь от request до response в Джанго

Веб-приложение или веб-сайт вращаются вокруг цикла запрос-ответ, и приложения Django не являются исключением. Но это не просто двухэтапный процесс. Наши приложения Django должны пройти различные стадии, чтобы вернуть конечному пользователю результат. Чтобы лучше понять структуру Django, мы должны понимать, как инициируются запросы и как конечный результат передается конечному пользователю. В статье объясняются различные этапы запросов и используемое там программное обеспечение или код.

Выпущен релиз-кандидат Django 3.0

Кандидат 1 релиза Django 3.0 - это последняя возможность для вас испытать множество новых функций перед выпуском Django 3.0.

Django DetailView - основы использования

Django позволяет создавать приложения очень легко. Если приложение должно быть выпущено быстро и является относительно общим, то эта среда Python идеально подходит для этого. В течение нескольких лет я профессионально работал в этой среде и часто рылся внутри, поэтому знаю почти всё, и сегодня я представлю вам все, что нужно знать, чтобы эффективно использовать универсальный DetailView в Django.

Выпущены исправления Django: 2.2.7, 2.1.14 и 1.11.26

Сегодня команда разработчиков Django выпустила версии 2.2.7, 2.1.14 и 1.11.26 с исправлениями ошибок. Пакет и контрольные суммы доступны на странице загрузок, а также из индекса пакетов Python. Идентификатор ключа PGP, использованный в этом выпуске: Mariusz Felisiak: 2EF56372BA48CD1B.

Как заставить request.is_ajax() работать с JS fetch()

Объект запроса Django request имеет изящный небольшой метод is_ajax(). Он позволяет определить, поступил ли запрос от JS-фреймворка (он же ajax старой школы). Хотя он отлично работает с некоторыми библиотеками JS, включая почтенный jQuery, он не будет работать с современным встроенным в JS fetch().

Практика программирования на Python 3, лекция №5

Лекции о Python 3 от Тимофея Хирьянова при поддержке Московского физико-технического института. Лекция №5.

Практика программирования на Python 3, лекция №4

Лекции о Python 3 от Тимофея Хирьянова при поддержке Московского физико-технического института. Лекция №4.

Практика программирования на Python 3, лекция №3

Лекции о Python 3 от Тимофея Хирьянова при поддержке Московского физико-технического института. Лекция №3.