Django媒体文件和AWS S3
Django静态文件与AWS S3 – Qiita
Django媒体文件与AWS S3 – Qiita
这篇文章是关于使用Django创建的” Django Blog” (暂定名)进行的调查总结。虽然是我第一次使用Django,但在大约3个星期内完成了制作。虽然是α版,请注册用户进行尝试。这是已经部署到GAE上的版本。
本文将总结有关Django媒体文件处理以及上传至AWS S3的内容。
在Django中,我们将通过FileField和ImageField上传的文件称为媒体文件。
表格字段-公式文件
1.将文件上传到本地 – 开发环境(DEBUG=True)
创建一个测试项目
python -m venv localupload
source localupload/bin/activate
cd localupload/
pip freeze
pip install django
django-admin startproject localupload .
这是用于从远程访问的设置。
---
ALLOWED_HOSTS = ["www.mypress.jp"]
---
我将在此处确认项目是否正在运行。
python manage.py migrate
python manage.py runserver 0:8080
1-2.上传至本地
我将创建一个用于将文件上传至本地的应用程序。
python manage.py startapp uploadapp
---
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'uploadapp',
]
---
---
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
---
-
- MEDIA_URL : メディアファイル公開時のURLのプレフィクス。url=http://アプリのドメイン+MEDIA_URL+メディアファイル名
- MEDIA_ROOT : サーバから見たメディアルートの絶対パス. プロジェクトトップディレクトリ/media
from django.conf import settings
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('uploadapp.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
在开发中(DEBUG=True)时,可以通过添加最后一个代码片段来保存图像到本地存储的MEDIA_ROOT,并且可以通过本地URL(MEDIA_URL)相对路径进行引用。但是在生产环境中(DEBUG=False),不推荐使用这种方法,应该像处理静态文件一样处理。
管理静态文件(如图像、JavaScript、CSS等)- 官方文档
Django静态文件与AWS S3- Qiita 的对接
from django.urls import path
from . import views
urlpatterns = [
path('', views.Photo.as_view()),
]
嗯,這次我們使用的是ImageField而不是FileField。ImageField是這樣的一個東西。
-
- ImageFieldは画像を扱うことに特化したFileFieldの派生フィールドです
-
- ImageFieldにはPillowが必要。
-
- 登録時のバリデーションで画像ファイルのチェックをする。画像ファイルでないもの、データの破損があるものは登録エラーとする(専用エラーメッセージあり)。
- 管理用のフィールドを事前に用意すると、登録時に画像の高さと幅(pixel単位)を取得して保存する
现在我们来安装Pillow。
pip install Pillow
使用 ImageField 定义 models。
from django.db import models
class PhotoModel(models.Model):
image = models.ImageField(upload_to='images')
def __str__(self):
return self.image.url
我将定义表单。
from django import forms
from .models import PhotoModel
class PhotoForm(forms.ModelForm):
class Meta:
model = PhotoModel
fields = '__all__'
给出定义。
from django.views import generic
from .forms import PhotoForm
from .models import PhotoModel
class Photo(generic.CreateView):
model = PhotoModel
form_class = PhotoForm
template_name = 'uploadapp/upload.html'
success_url = '/'
def get_context_data(self, **kwargs):
context = super(Photo, self).get_context_data(**kwargs) # はじめに継承元のメソッドを呼び出す
context["photos"] = PhotoModel.objects.all()
return context
创建模板文件夹。
mkdir -p uploadapp/templates/uploadapp/
这是一个上传表单和已上传图片列表的显示。
<form action="" method="POST" enctype="multipart/form-data">{% csrf_token %} {{ form.as_p }}
<button type="submit">アップロード</button>
</form>
{% for photo in photos %}
<a href="{{ photo.image.url }}">{{ photo }}</a>
<hr>
{% endfor %}
我们开始启动项目
python manage.py runserver 0:8080
这是已经上传了两张图片的界面。

请根据 MEDIA_URL 的配置,查看以下的HTML源代码。图片的链接展示形式为 photo.image.url=”/media/images/tree5.jpg”。
<form action="" method="POST" enctype="multipart/form-data"><input type="hidden" name="csrfmiddlewaretoken" value="m0qzyYvLhuUckbF5ctHAAJOCThqZ24Q7RE5c70EQ4bnTm05v3F33aYrn7br4jed2">
<p><label for="id_image">Image:</label> <input type="file" name="image" accept="image/*" required id="id_image"></p>
<button type="submit">アップロード</button>
</form>
<a href="/media/images/tree4jpeg.jpeg">/media/images/tree4jpeg.jpeg</a>
<hr>
<a href="/media/images/tree5.jpg">/media/images/tree5.jpg</a>
<hr>
请确认设置了MEDIA_ROOT。 这是在项目顶级目录下运行tree命令的结果。
$ tree media/
media/
├── images
│ ├── tree4jpeg.jpeg
│ └── tree5.jpg
└── tree4jpeg.jpeg
2.将数据上传到远程 AWS S3 – 生产环境(DEBUG=False)
从这里开始,我们将查看将图像上传到AWS S3的设置。由于这是生产环境,我们将进行基本设置,将静态文件部署到AWS S3,并进行额外设置,将媒体文件上传到AWS S3。
请参考「Django static文件和AWS S3 – Qiita」以了解关于静态文件和AWS设置的信息。
首先是设定生产环境。
---
DEBUG = False
---
我将在AWS S3中创建一个新的存储桶,并为它添加以下策略。
{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"AddPerm",
"Effect":"Allow",
"Principal": "*",
"Action":["s3:GetObject"],
"Resource":["arn:aws:s3:::media-test-reiwa/*"]
}
]
}
请安装所需的库。
pip install boto3
pip install django-storages
打开图书馆。
---
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'uploadapp',
'storages', # 追加
]
---
# STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
AWS_ACCESS_KEY_ID = 'AKIAXXXXXXXXXXXXXXXXXXXXX'
AWS_SECRET_ACCESS_KEY = 'YYYYYYYYYYYYYYYYYYYYYY'
AWS_STORAGE_BUCKET_NAME = 'media-test-reiwa'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = None
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
DEFAULT_FILE_STORAGE = 'localupload.storage_backends.MediaStorage'
除了静态文件的配置之外,还添加了DEFAULT_FILE_STORAGE的配置。
静态资产和媒体资产的解释
-
- static ファイルはSTATICFILES_STORAGE=S3Boto3Storageで設定。collectstaticが処理する。
- media ファイルはDEFAULT_FILE_STORAGEで設定。S3Boto3Storageを拡張し、’media’ディレクトリにアップロードするよう指定する。
扩展S3Boto3Storage是通过以下的storage_backends.py来进行的,该扩展会按照在DEFAULT_FILE_STORAGE中指定的方式操作。设置了当上传相同文件名的图片时,不会覆盖原有图片,而会自动重命名。
from storages.backends.s3boto3 import S3Boto3Storage
# 画像は同ファイル名での上書きを許さない
class MediaStorage(S3Boto3Storage):
location = 'media'
file_overwrite = False
创建一个”static”目录,并通过collectstatic将static文件部署到AWS S3。
mkdir static
python manage.py collectstatic
在这里,我们将从数据库表中删除之前上传的所有条目。
启动项目并上传两个图像文件。
python manage.py runserver 0:8080
你可以在以下画面中确认到这样的内容。

AWS S3的存储桶中有static和media目录。

媒体目录中确实上传了2个文件。

这次就这样吧。