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_todefines an upload directory, where uploaded files should are (similar to FileField)accepted_typesdefines 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 = filedjango-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."
}