如何使用 django 应用程序在 AWS S3 中上传文件?
How to upload file in AWS S3 with django app?
我在上传用户个人资料图片时遇到问题。现在,当我在 Django 管理中创建一个用户并从管理仪表板上传一个文件时,它工作正常并且没有错误。它应该进入我的 AWS S3 存储桶,但这显然是不可行的,我一直在寻找解决方案 3 到 4 天,但没有成功或任何令人满意的结果。我显然不会向用户提供仪表板访问权限。使用的数据库是MongoDB,数据库引擎是djongo。
这是我的 settings.py
INSTALLED_APPS = [
'profileupload',
's3direct',
'storages',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.humanize',
]
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
AWS_SECRET_ACCESS_KEY = 'MY_SPECIAL_KEY'
AWS_ACCESS_KEY_ID = 'MY_SPECIAL_KEY_NAME'
AWS_STORAGE_BUCKET_NAME = 'S3_BUCKET'
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
我的urls.py
from django.urls import path, include
from .views import signup_form
urlpatterns = [
path('signup', signup_form, name='signup'),
]
我的models.py
class profile(models.Model):
profile_id = models.AutoField(primary_key=True,unique=True)
profile_username = models.CharField(max_length=100,unique=True)
profile_name = models.CharField(max_length=150)
profile_email = models.EmailField(max_length=200)
profile_create_time = models.DateField(auto_now_add=True)
profile_dob = models.DateField()
profile_password = models.CharField(max_length=50, null=True)
profile_picture = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return str(self.profile_username)
我的views.py
def signup_form(request):
if request.method == 'POST':
if request.POST.get('profile_username') and request.POST.get('profile_name') and request.POST.get('profile_email') and request.POST.get('profile_dob') and request.POST.get('profile_password') and request.POST.get('profile_picture'):
pr = profile()
pr.profile_username = request.POST.get('profile_username')
pr.profile_name = request.POST.get('profile_name')
pr.profile_email = request.POST.get('profile_email')
pr.profile_password = request.POST.get('profile_password')
pr.profile_dob = request.POST.get('profile_dob')
pr.profile_picture = request.POST.get('profile_picture')
try:
pr.save()
print('setProfile success')
return redirect('index.html')
except Exception as e:
return render(request, 'signup.html')
return render(request, 'signup.html')
else:
return render(request, 'signup.html')
我的注册表单'signup.html'
{% extends 'index.html' %}
{% block content %}
<form method='POST'>
{% csrf_token %}
<div>
<label>USERNAME</label>
<input type="text" placeholder="" name="profile_username" required/>
</div><br>
<div>
<label>NAME</label>
<input type="text" placeholder="" name="profile_name" required/>
</div><br>
<div>
<label>EMAIL</label>
<input type="email" placeholder="" name="profile_email" required/>
</div><br>
<div>
<label>Password</label>
<input type="password" placeholder="" name="profile_password" required/>
</div><br>
<div>
<label>DOB</label>
<input type="date" placeholder="" name="profile_dob" required/>
</div><br>
<div>
<label>Profile Picture</label>
<input type="file" placeholder="" name="profile_picture" required/>
</div><br>
<button type="submit">submit</button>
</form>
<a href="/">Home</a>
{% endblock content %}
此外,我想更改上传文件的名称,Django admin 上传的文件采用原样的文件名,但是当我将此应用程序公开给 public 文件时名称必须正确以避免被覆盖或多次使用相同的文件
好的,所以我想到了在 views.py
中应用错误的访问密钥和输入错误的信息
首先在views.py
中进行正确的输入
pr.profile_picture = request.POST.get('profile_picture')
不用上面的方法,下面的方法会有所帮助:
pr.profile_picture = request.FILES["profile_picture"]
另外,当我将上面的代码与 单引号 一起使用时,它不会起作用,所以请记住这一点。
正在上传文件到 S3
现在还有一些其他方法可以做到这一点,但同时更改文件名。
我另外制作了一个文件专门用来处理图片,并改了文件名。
import boto3
session = boto3.Session(
aws_access_key_id= 'secret sauce',
aws_secret_access_key = 'secret sauce'
)
class image():
def UploadImage(name,image):
filename = name+'_picture.jpg'
imagedata = image
s3 = boto3.resource('s3')
try:
object = s3.Object('bucket sauce', filename)
object.put(ACL='public-read',Body=imagedata,Key=filename)
return True
except Exception as e:
return e
以上方法在views.py
中被调用
ret = image.UploadImage(pr.profile_username,pr.profile_picture)
放在try块中避免出错。
如前所述,一种方法是直接使用 boto3
库。
另一种方法是使用 django-storages
的 save
功能(它还在后台使用 boto3
)。
如果只有 1 个桶:
settings.py
...
INSTALLED_APPS = [
...
"storages",
...
]
...
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_ACCESS_KEY_ID = 'my-access-key-id'
AWS_SECRET_ACCESS_KEY = 'my-secret-access-key'
# Depending on the AWS account used, you might also need to declare AWS_SESSION_TOKEN as an environment variable
AWS_STORAGE_BUCKET_NAME = 'my-bucket'
...
views.py
from io import BytesIO
from django.core.files.storage import default_storage
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(('GET',))
def save_file(request):
file_name = "toguro.txt"
file_content = b"I have my full 100% power now!"
file_content_io = BytesIO(file_content)
default_storage.save(file_name, file_content_io)
return Response({"message": "File successfully saved"})
如果有很多桶:
settings.py
...
INSTALLED_APPS = [
...
"storages",
...
]
...
AWS_ACCESS_KEY_ID = 'my-access-key-id'
AWS_SECRET_ACCESS_KEY = 'my-secret-access-key'
# Depending on the AWS account used, you might also need to declare AWS_SESSION_TOKEN as an environment variable
...
views.py
from io import BytesIO
from rest_framework.decorators import api_view
from rest_framework.response import Response
from storages.backends.s3boto3 import S3Boto3Storage
# For a clear separation-of-concern, you should consider placing this code to its appropriate place
class MyStorage1(S3Boto3Storage):
bucket_name = 'my-bucket-1'
class MyStorage2(S3Boto3Storage):
bucket_name = 'my-bucket-2'
@api_view(('GET',))
def save_file(request):
file_name_1 = "toguro.txt"
file_name_2 = "sensui.txt"
file_content_1 = b"I have my full 100% power now!"
file_content_2 = b"I will release the S-Class demons!"
file_content_io_1 = BytesIO(file_content_1)
file_content_io_2 = BytesIO(file_content_2)
storage1 = MyStorage1()
storage2 = MyStorage2()
storage1.save(file_name_1, file_content_io_1)
storage2.save(file_name_2, file_content_io_2)
return Response({"message": "File successfully saved"})
我在上传用户个人资料图片时遇到问题。现在,当我在 Django 管理中创建一个用户并从管理仪表板上传一个文件时,它工作正常并且没有错误。它应该进入我的 AWS S3 存储桶,但这显然是不可行的,我一直在寻找解决方案 3 到 4 天,但没有成功或任何令人满意的结果。我显然不会向用户提供仪表板访问权限。使用的数据库是MongoDB,数据库引擎是djongo。
这是我的 settings.py
INSTALLED_APPS = [
'profileupload',
's3direct',
'storages',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.humanize',
]
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
AWS_SECRET_ACCESS_KEY = 'MY_SPECIAL_KEY'
AWS_ACCESS_KEY_ID = 'MY_SPECIAL_KEY_NAME'
AWS_STORAGE_BUCKET_NAME = 'S3_BUCKET'
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
我的urls.py
from django.urls import path, include
from .views import signup_form
urlpatterns = [
path('signup', signup_form, name='signup'),
]
我的models.py
class profile(models.Model):
profile_id = models.AutoField(primary_key=True,unique=True)
profile_username = models.CharField(max_length=100,unique=True)
profile_name = models.CharField(max_length=150)
profile_email = models.EmailField(max_length=200)
profile_create_time = models.DateField(auto_now_add=True)
profile_dob = models.DateField()
profile_password = models.CharField(max_length=50, null=True)
profile_picture = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return str(self.profile_username)
我的views.py
def signup_form(request):
if request.method == 'POST':
if request.POST.get('profile_username') and request.POST.get('profile_name') and request.POST.get('profile_email') and request.POST.get('profile_dob') and request.POST.get('profile_password') and request.POST.get('profile_picture'):
pr = profile()
pr.profile_username = request.POST.get('profile_username')
pr.profile_name = request.POST.get('profile_name')
pr.profile_email = request.POST.get('profile_email')
pr.profile_password = request.POST.get('profile_password')
pr.profile_dob = request.POST.get('profile_dob')
pr.profile_picture = request.POST.get('profile_picture')
try:
pr.save()
print('setProfile success')
return redirect('index.html')
except Exception as e:
return render(request, 'signup.html')
return render(request, 'signup.html')
else:
return render(request, 'signup.html')
我的注册表单'signup.html'
{% extends 'index.html' %}
{% block content %}
<form method='POST'>
{% csrf_token %}
<div>
<label>USERNAME</label>
<input type="text" placeholder="" name="profile_username" required/>
</div><br>
<div>
<label>NAME</label>
<input type="text" placeholder="" name="profile_name" required/>
</div><br>
<div>
<label>EMAIL</label>
<input type="email" placeholder="" name="profile_email" required/>
</div><br>
<div>
<label>Password</label>
<input type="password" placeholder="" name="profile_password" required/>
</div><br>
<div>
<label>DOB</label>
<input type="date" placeholder="" name="profile_dob" required/>
</div><br>
<div>
<label>Profile Picture</label>
<input type="file" placeholder="" name="profile_picture" required/>
</div><br>
<button type="submit">submit</button>
</form>
<a href="/">Home</a>
{% endblock content %}
此外,我想更改上传文件的名称,Django admin 上传的文件采用原样的文件名,但是当我将此应用程序公开给 public 文件时名称必须正确以避免被覆盖或多次使用相同的文件
好的,所以我想到了在 views.py
中应用错误的访问密钥和输入错误的信息首先在views.py
中进行正确的输入pr.profile_picture = request.POST.get('profile_picture')
不用上面的方法,下面的方法会有所帮助:
pr.profile_picture = request.FILES["profile_picture"]
另外,当我将上面的代码与 单引号 一起使用时,它不会起作用,所以请记住这一点。
正在上传文件到 S3
现在还有一些其他方法可以做到这一点,但同时更改文件名。
我另外制作了一个文件专门用来处理图片,并改了文件名。
import boto3
session = boto3.Session(
aws_access_key_id= 'secret sauce',
aws_secret_access_key = 'secret sauce'
)
class image():
def UploadImage(name,image):
filename = name+'_picture.jpg'
imagedata = image
s3 = boto3.resource('s3')
try:
object = s3.Object('bucket sauce', filename)
object.put(ACL='public-read',Body=imagedata,Key=filename)
return True
except Exception as e:
return e
以上方法在views.py
中被调用ret = image.UploadImage(pr.profile_username,pr.profile_picture)
放在try块中避免出错。
如前所述,一种方法是直接使用 boto3
库。
另一种方法是使用 django-storages
的 save
功能(它还在后台使用 boto3
)。
如果只有 1 个桶:
settings.py
...
INSTALLED_APPS = [
...
"storages",
...
]
...
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_ACCESS_KEY_ID = 'my-access-key-id'
AWS_SECRET_ACCESS_KEY = 'my-secret-access-key'
# Depending on the AWS account used, you might also need to declare AWS_SESSION_TOKEN as an environment variable
AWS_STORAGE_BUCKET_NAME = 'my-bucket'
...
views.py
from io import BytesIO
from django.core.files.storage import default_storage
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(('GET',))
def save_file(request):
file_name = "toguro.txt"
file_content = b"I have my full 100% power now!"
file_content_io = BytesIO(file_content)
default_storage.save(file_name, file_content_io)
return Response({"message": "File successfully saved"})
如果有很多桶:
settings.py
...
INSTALLED_APPS = [
...
"storages",
...
]
...
AWS_ACCESS_KEY_ID = 'my-access-key-id'
AWS_SECRET_ACCESS_KEY = 'my-secret-access-key'
# Depending on the AWS account used, you might also need to declare AWS_SESSION_TOKEN as an environment variable
...
views.py
from io import BytesIO
from rest_framework.decorators import api_view
from rest_framework.response import Response
from storages.backends.s3boto3 import S3Boto3Storage
# For a clear separation-of-concern, you should consider placing this code to its appropriate place
class MyStorage1(S3Boto3Storage):
bucket_name = 'my-bucket-1'
class MyStorage2(S3Boto3Storage):
bucket_name = 'my-bucket-2'
@api_view(('GET',))
def save_file(request):
file_name_1 = "toguro.txt"
file_name_2 = "sensui.txt"
file_content_1 = b"I have my full 100% power now!"
file_content_2 = b"I will release the S-Class demons!"
file_content_io_1 = BytesIO(file_content_1)
file_content_io_2 = BytesIO(file_content_2)
storage1 = MyStorage1()
storage2 = MyStorage2()
storage1.save(file_name_1, file_content_io_1)
storage2.save(file_name_2, file_content_io_2)
return Response({"message": "File successfully saved"})