简体   繁体   中英

How to upload an image in django using S3Boto3Storage where the path is set dynamically from the view in django

I'm wanting to save images to an S3 bucket using the session_key as the directory inside the bucket, in django.

I have created a test page that uploads an image to a set location in the bucket but don't know how to use the session_key to set the upload location dynamically.

I've looked at the docs for django-storages and I can see a way to do this if it wasn't for the fact that I am using a ModelForm .

Here is the code I have (I have omitted my settings.py with the bucket name and credentials):

storage_backends.py

from storages.backends.s3boto3 import S3Boto3Storage

class TestS3MediaStorage(S3Boto3Storage):
    location = 'dev/'
    default_acl = 'public-read'
    file_overwrite = False

models.py

from .storage_backends import TestS3MediaStorage

class TestS3Upload(models.Model):
    uploaded_at = models.DateTimeField(auto_now_add=True)
    file = models.FileField(storage=TestS3MediaStorage())

forms.py

from .models import TestS3Upload

class TestS3UploadForm(forms.ModelForm):

    class Meta:
        model = TestS3Upload
        fields = ['file']

views.py

from django.shortcuts import render
from django.http import HttpResponse

from .forms import TestS3UploadForm

def test_s3_upload(request):

    # create session if it doesn't already exist
    if not request.session.session_key:
        request.session.create()

    # not quite sure how to use this to set upload destination
    session_key = request.session.session_key

    if request.method == 'POST':

        form = TestS3UploadForm(request.POST, request.FILES)

        if form.is_valid():
            form.save()
            return HttpResponse("upload successful!")
    else:
        form = TestS3UploadForm()

    return render(
        request,
        'uploader/test_s3_upload.html',
        {
            'form': form
        }
    )

test_s3_upload.html

<h1>Test S3 file upload</h1>
<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Upload photo to S3 Bucket</button>
</form>

显示上传图片的模板页面截图

When I run my code and upload an image, for example car.jpg , it uploads successfully but the path inside the S3 bucket is

<bucket-name>/dev/car.jpg

and i want

<bucket-name>/dev/<session-key>/car.jpg

The packages needed are boto3 and django-storages in case anyone who wants to help answer needs to know.

I have figured out a way to upload an image/file to s3 to a directory using the session key. It also works for uploading a file in general, not just s3.

First I added an attribute to the model to store the session key.

class TestS3Upload(models.Model):
    session_key = models.CharField(max_length=50, null=False, blank=False)
    ...

Then I included a hidden field on the modelform that I pre-populated with the session_key value in the view.

forms.py

class TestS3UploadForm(forms.ModelForm):

    class Meta:
        model = TestS3Upload
        fields = ['file', 'session_key']
        widgets = {'session_key': forms.HiddenInput()}

views.py

def test_s3_upload(request):
    # create session if it doesn't already exist
    if not request.session.session_key:
        request.session.create()

    session_key = request.session.session_key
    ...
    form = TestS3UploadForm(initial={'session_key': session_key})

Then I created a function in my models.py that returns a path using the session_key from the model and set the model's file field upload_to attribute to this function

...
import os

def upload_to_session_key_dir(instance, filename):
    return os.path.join(instance.session_key, filename)

class TestS3Upload(models.Model):
    session_key = models.CharField(max_length=50, null=False, blank=False)
    uploaded_at = models.DateTimeField(auto_now_add=True)

    file = models.FileField(upload_to=upload_to_session_key_dir)

When saving the form now it uploads the file inside a directory with the session_key.

final views.py

from django.shortcuts import render
from django.http import HttpResponse
from .forms import TestS3UploadForm
from .models import TestS3Upload

def test_s3_upload(request):

    # create session if it doesn't already exist
    if not request.session.session_key:
        request.session.create()

    session_key = request.session.session_key

    if request.method == 'POST':

        form = TestS3UploadForm(request.POST, request.FILES)

        if form.is_valid():
            form.save()

            filename = "{}/{}".format(session_key, form.cleaned_data['file'].name)
            s3_upload_path = TestS3Upload.objects.get(file=filename).file.url

            return HttpResponse("Image successfully uploaded to bucket at location: {}".format(s3_upload_path))
    else:
        form = TestS3UploadForm(initial={'session_key': session_key})

    return render(
        request,
        'upload/test_s3_upload.html',
        {
            'form': form
        }
    )

The template for the view test_s3_upload.html remained the same.

上传成功消息,其中包含上传文件的完整 url 路径

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM