使用 Boto3 在 Django 上上传

Ric*_*vis 4 python django upload boto3

所以我一直在 Django 网站上工作,但我陷入了困境。我似乎不知道如何正确使用 Boto3 将文件上传到数字海洋空间。我有一个 python 脚本可以执行我想要的操作,但我不知道如何使其在网页上与 Django 一起使用。我已经阅读了大量文档,但似乎找不到明确的答案。此外,所有示例都使用 AWS。这是我到目前为止的代码:

Python上传脚本:

from boto3 import session
from botocore.client import Config

ACCESS_ID = '-----'
SECRET_KEY = '-----'

# Initiate session
session = session.Session()
client = session.client('s3',
                        region_name='nyc3',
                        endpoint_url='https://nyc3.digitaloceanspaces.com',
                        aws_access_key_id=ACCESS_ID,
                        aws_secret_access_key=SECRET_KEY)

# Upload file to Space 'from folder/file','space to put','name it will become'


def run(upfile):
    client.upload_file(upfile, 'yl2-test', 'test/storage-test')
Run Code Online (Sandbox Code Playgroud)

视图.py:

from django.shortcuts import render
from django.shortcuts import redirect
from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect

from .forms import CharacterForm, SignUpForm

from scripts.test_upload import run


def index(request):
    return render(request, 'YL2/index.html')


def new_char(request):
    # return render(request, 'YL2/new_char.html')
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = CharacterForm(request.POST, request.FILES)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            run(request.FILES['char_file'])
            run(request.FILES['char_image'])
            # redirect to a (success page) new URL:
            return HttpResponseRedirect('')

    # if a GET (or any other method) we'll create a blank form
    else:
        form = CharacterForm()

    return render(request, 'YL2/new_char.html', {'form': form})


def log_in_page(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        return redirect('index')
    else:
        return HttpResponseRedirect('Login error. Try again.')


def SignUp(request):
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            raw_password = form.cleaned_data.get('password1')
            user = authenticate(username=username, password=raw_password)
            login(request, user)
            return redirect('index')
    else:
        form = SignUpForm()
    return render(request, 'signup.html', {'form': form})
Run Code Online (Sandbox Code Playgroud)

模型.py:

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver


class UserProfile(models.Model):
    # -----


class Character(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    char_name = models.CharField(max_length=100)
    char_image = models.ImageField()
    char_file = models.FileField(max_length=100)
    # upload_to='uploads/'

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)


@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.userprofile.save()
Run Code Online (Sandbox Code Playgroud)

形式.py:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User


class CharacterForm(forms.Form):
    char_name = forms.CharField(label='Character Name', max_length=100)
    char_image = forms.ImageField(label='Character Image')
    char_file = forms.FileField(label='Character File')


class SignUpForm(UserCreationForm):
    email = forms.EmailField(max_length=254, help_text='Required. Input a valid email address.')

    class Meta:
        model = User
        fields = ('username', 'email', 'password1', 'password2', )
Run Code Online (Sandbox Code Playgroud)

new_char.html:

<h1>New Character for: {{ user.username }}</h1>


<form enctype="multipart/form-data" action="/new_char/" method="post">
    {% csrf_token %}
    {{ form.as_ul }}<br><br>
    <input type="submit" value="Submit" />
</form>
Run Code Online (Sandbox Code Playgroud)

编辑:

添加带有完整跟踪信息的错误。

错误:

ValueError at /new_char/
Filename must be a string
Request Method: POST
Request URL:    http://127.0.0.1:8000/new_char/
Django Version: 2.0.4
Exception Type: ValueError
Exception Value:    
Filename must be a string
Exception Location: /usr/local/lib/python3.6/site-packages/boto3/s3/transfer.py in upload_file, line 273
Python Executable:  /usr/local/opt/python/bin/python3.6
Python Version: 3.6.5
Python Path:    
['/Users/---user---/code/---project---',
 '/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python36.zip',
 '/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6',
 '/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload',
 '/Users/---user---/Library/Python/3.6/lib/python/site-packages',
 '/usr/local/lib/python3.6/site-packages']
Server time:    Wed, 13 Jun 2018 11:00:26 -0600
Run Code Online (Sandbox Code Playgroud)

痕迹:

Environment:


Request Method: POST
Request URL: http://127.0.0.1:8000/new_char/

Django Version: 2.0.4
Python Version: 3.6.5
Installed Applications:
['YL2.apps.Yl2Config',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  35.             response = get_response(request)

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/---user---/code/---project---/YL2/views.py" in new_char
  24.             run(request.FILES['char_file'])

File "/Users/---user---/code/---project---/scripts/test_upload.py" in run
  20.     client.upload_file(upfile, 'yl2-test', 'test/storage-test')

File "/usr/local/lib/python3.6/site-packages/boto3/s3/inject.py" in upload_file
  131.             extra_args=ExtraArgs, callback=Callback)

File "/usr/local/lib/python3.6/site-packages/boto3/s3/transfer.py" in upload_file
  273.             raise ValueError('Filename must be a string')

Exception Type: ValueError at /new_char/
Exception Value: Filename must be a string
Run Code Online (Sandbox Code Playgroud)

Dan*_*man 5

upload_file方法用于上传存储在本地磁盘上并通过其文件名引用的文件,因此它希望您将该文件名作为字符串传递。

相反,您应该使用upload_fileobj,它从对象上传文件 - 这就是您所拥有的。

(请注意,这与 AWS 和 DigitalOcean 之间的任何差异无关。)