django-buckets provides a Django storage system (S3Storage
) to store files on
Amazon S3. Besides the storage itself, the
library comes with a custom model field (S3FileField
) to reference
files in Django and a form widget that handles uploading files to S3 using
pre-signed URLs.
For testing and development, django-buckets offers S3FakeStorage
and
the API endpoint /media/s3/uploads
, which mimics the behavior of
S3Storage
and AWS S3's file upload API but use the local file system.
Both integrate seamlessly with S3FileField
.
django-buckets is work in progress and not stable. Things might break.
- Python 3.4 or 3.5
- Django 1.11 or 2.0
pip install django-buckets
In settings, add buckets
to installed apps and set S3Storage
as default storage. Configure the AWS
settings by providing the S3
bucket name AWS access key and secret key and the AWS region where your
bucket is located.
INSTALLED_APPS = (
...
'buckets',
)
DEFAULT_FILE_STORAGE = 'buckets.storage.S3Storage'
AWS = {
'BUCKET': 'some-bucket',
'ACCESS_KEY': 'J36RZO0MO9JQ6NWAOY2I',
'SECRET_KEY': 'EaANd90ZdgiykkXEf67fNRnhc96zcGnkgDhagj6v',
'REGION': 'us-east-1'
}
Include django-buckets' URLs to add an API endpoint, which is used by the form widget or REST-clients to request valid signed URLs.
urlpatterns = [
url(r'', include('buckets.urls')),
]
Edit the CORS policy of the S3 bucket you intend to use to allow for POST requests:
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
In settings, add buckets
to installed apps and set
FakeS3Storage
as default default storage.
DEFAULT_FILE_STORAGE = 'buckets.test.storage.FakeS3Storage'
Include django-buckets' URLs to add an API endpoint, which is used by the form widget or REST-clients to request valid signed URLs. Further, it will add a file upload endpoint, which behaves like S3's file upload but stores files on the local file system, so you don't need to configure an S3 bucket for development.
INSTALLED_APPS = (
...
'buckets',
)
urlpatterns = [
url(r'', include('buckets.test.urls')),
]
Other optional settings can be added to the AWS
settings dictionary.
Name | Type | Description |
---|---|---|
MAX_FILE_SIZE |
int |
The maximum allowed size for file uploads in bytes. If MAX_FILE_SIZE is not defined then there will be no limit to the size of file. |
Create a model class, which has an S3FileField
. Internally, S3FileField
is a Django CharField
and it accepts the same arguments.
S3FileField
accepts two additional optional arguments:
upload_to
defines an upload directory, where uploaded files should are (similar to FileField)accepted_types
defines a list mime types that are accepted to upload. If you do not provide this argument, all types will be accepted.
from django.db import models
from buckets.fields import S3FileField
class MyModel(models.Model):
name = models.CharField(max_length=200)
file = S3FileField(upload_to='some-dir',
accepted_types=['image/png', 'image/jpeg'])
An S3FileField
accepts an URL as its value:
file_model = MyModel.objects.create(
name='My File',
file='https://s3.amazonaws.com/some-bucket/file.txt'
)
Internally, an instance of S3File
is created from the URL that provides
access to the file itself.
# downloads the file and returns a File object
file = file_model.file.open()
# assign an updated file
file_model.file = file
django-buckets comes with a form widget that takes care of uploading files, displaying links to files and filling the form fields. It's the easiest way to use django-buckets in your application.
To use the widget, make sure the widget's media files (some JS and CSS) are
added to the template, ideally somewhere in the page's head
:
<html>
<head>
<meta charset="utf-8">
<title>django-buckets File Upload</title>
{{ form.media }}
</head>
...
</html>
You can use Django's standard form rendering methods and the necessary HTML elements are added to the page:
<html>
...
<body>
{{ form.as_p }}
</body>
</html>
If you plan to use a custom widget in your forms, you can add a Django
CharField
to your form and provide the widget you want to use:
from django import forms
from .models import MyModel
class MyModelForm(forms.ModelForm):
file = forms.CharField(widget=MyWidget)
class Meta:
model = MyModel
fields = ['name', 'file']
If you are building an API-only application, you can get a signed URL by
POSTing client_method
and http_method
.
POST /s3/signed-url/ Accept: application/json Content-Type: application/json { "key": "file.txt" }
HTTP/1.1 200 OK Content-Type: application/json { "url": "https://s3.amazonaws.com/some-bucket", "fields": { "key": "file.txt", "x-amz-credential": "HKJXXOZ7L71OMC9S830I/20160425/us-east-1/s3/aws4_request", "policy": "AORKx5gcfIIMJQUyKAkdCUDapV99I8PAn592rjN2of6Hodk1HNiFrj1ItWdJpuQiwrYVi0NJMnfCxfmfVlZg9NDpKFQi8b5vSpWpamMu5UVUdg9c8A77lF1fuWOty8Xx4qUza8EXxuz49mYYRhRym8TRNzx4v9qDwPmILe6FRl7BGSlIijn46Td9OroAHJoUPp2YU1dwsGOXGZufCGHJ8C3m1vM0YmPhDTvt2WABGscgqJmKB57SkKmnixCWYhoy", "x-amz-date": "20160425T180721Z", "x-amz-algorithm": "AWS4-HMAC-SHA256", "x-amz-signature": "bOSxtzlFNaoAfa6rzjimXBN1KIE1uQ8k1h1sCn0U7lvwYK8whuflP5PcFU8KgzxQ" } }
To upload the file to AWS S3, send the file via POST to the URL given in the
response and include all fields
with the request payload.
POST https://s3.amazonaws.com/some-bucket Content-Type:multipart/form-data; boundary=----WebKitFormBoundary7LwCXdHGMv2KBDza ------WebKitFormBoundary7LwCXdHGMv2KBDza Content-Disposition: form-data; name="key" file.txt ------WebKitFormBoundary7LwCXdHGMv2KBDza Content-Disposition: form-data; name="x-amz-algorithm" AWS4-HMAC-SHA256 ------WebKitFormBoundary7LwCXdHGMv2KBDza Content-Disposition: form-data; name="x-amz-date" 20160425T180721Z ------WebKitFormBoundary7LwCXdHGMv2KBDza Content-Disposition: form-data; name="x-amz-signature" bOSxtzlFNaoAfa6rzjimXBN1KIE1uQ8k1h1sCn0U7lvwYK8whuflP5PcFU8KgzxQ ------WebKitFormBoundary7LwCXdHGMv2KBDza Content-Disposition: form-data; name="policy" AORKx5gcfIIMJQUyKAkdCUDapV99I8PAn592rjN2of6Hodk1HNiFrj1ItWdJpuQiwrYVi0NJMnfCxfmfVlZg9NDpKFQi8b5vSpWpamMu5UVUdg9c8A77lF1fuWOty8Xx4qUza8EXxuz49mYYRhRym8TRNzx4v9qDwPmILe6FRl7BGSlIijn46Td9OroAHJoUPp2YU1dwsGOXGZufCGHJ8C3m1vM0YmPhDTvt2WABGscgqJmKB57SkKmnixCWYhoy ------WebKitFormBoundary7LwCXdHGMv2KBDza Content-Disposition: form-data; name="x-amz-credential" HKJXXOZ7L71OMC9S830I/20160425/us-east-1/s3/aws4_request ------WebKitFormBoundary7LwCXdHGMv2KBDza Content-Disposition: form-data; name="file" Content-Disposition: form-data; name="file"; filename="file.txt" Content-Type: application/octet-stream ------WebKitFormBoundary7LwCXdHGMv2KBDza
POST /s3/delete-resource/ Accept: application/json Content-Type: application/json { "key": "file.txt" }
When the file was deleted successfully:
HTTP/1.1 204 No Content
When the file was not found:
HTTP/1.1 400 Bad Request Content-Type: application/json { "error": "S3 resource does not exist." }