Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
88 views
in Technique[技术] by (71.8m points)

python - 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>

screenshot of rendered template page showing upload of image

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.

question from:https://stackoverflow.com/questions/65874537/how-to-upload-an-image-in-django-using-s3boto3storage-where-the-path-is-set-dyna

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

Upload success message with full url path to uploaded file


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...