{"id":13469292,"url":"https://github.com/bradleyg/django-s3direct","last_synced_at":"2026-04-10T10:02:35.754Z","repository":{"id":7440723,"uuid":"8781168","full_name":"bradleyg/django-s3direct","owner":"bradleyg","description":"Directly upload files to S3 compatible services with Django.","archived":false,"fork":false,"pushed_at":"2024-02-11T07:07:36.000Z","size":1232,"stargazers_count":669,"open_issues_count":41,"forks_count":239,"subscribers_count":24,"default_branch":"master","last_synced_at":"2026-03-22T01:00:49.616Z","etag":null,"topics":["aws","django","django-s3direct","python","s3","storages","uploads"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"sahat/hackathon-starter","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bradleyg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-03-14T17:29:39.000Z","updated_at":"2026-03-08T18:19:05.000Z","dependencies_parsed_at":"2024-06-18T16:52:49.248Z","dependency_job_id":"c26a9495-1cb8-4e4a-bd5d-94bace1555bf","html_url":"https://github.com/bradleyg/django-s3direct","commit_stats":{"total_commits":377,"total_committers":48,"mean_commits":7.854166666666667,"dds":"0.49336870026525204","last_synced_commit":"dadb400addba7f86d30b00bf50b55b89ea2694d5"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/bradleyg/django-s3direct","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradleyg%2Fdjango-s3direct","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradleyg%2Fdjango-s3direct/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradleyg%2Fdjango-s3direct/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradleyg%2Fdjango-s3direct/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bradleyg","download_url":"https://codeload.github.com/bradleyg/django-s3direct/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradleyg%2Fdjango-s3direct/sbom","scorecard":{"id":250350,"data":{"date":"2025-08-11","repo":{"name":"github.com/bradleyg/django-s3direct","commit":"dadb400addba7f86d30b00bf50b55b89ea2694d5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/run-tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":1,"reason":"Found 3/20 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/run-tests.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/bradleyg/django-s3direct/run-tests.yml/master?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/run-tests.yml:18","Warn: pipCommand not pinned by hash: .github/workflows/run-tests.yml:21","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENCE:0","Info: FSF or OSI recognized license: MIT License: LICENCE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 13 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"46 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2014-5 / GHSA-296w-6qhq-gf92","Warn: Project is vulnerable to: PYSEC-2011-2 / GHSA-3jqw-crqj-w8qw","Warn: Project is vulnerable to: PYSEC-2012-3 / GHSA-59w8-4wm2-4xw8","Warn: Project is vulnerable to: PYSEC-2012-4 / GHSA-5h2q-4hrp-v9rr","Warn: Project is vulnerable to: PYSEC-2014-6 / GHSA-625g-gx8c-xcmg","Warn: Project is vulnerable to: PYSEC-2015-8 / GHSA-6565-fg86-6jcx","Warn: Project is vulnerable to: PYSEC-2021-98 / GHSA-68w8-qjq3-2gfm","Warn: Project is vulnerable to: PYSEC-2012-2 / GHSA-78vx-ggch-wghm","Warn: Project is vulnerable to: PYSEC-2015-9 / GHSA-7fq8-4pv5-5w5c","Warn: Project is vulnerable to: PYSEC-2015-4 / GHSA-7qfw-j7hp-v45g","Warn: Project is vulnerable to: PYSEC-2011-9 / GHSA-7wph-fc4w-wqp2","Warn: Project is vulnerable to: GHSA-7xr5-9hcq-chf9","Warn: Project is vulnerable to: PYSEC-2014-2 / GHSA-89hj-xfx5-7q66","Warn: Project is vulnerable to: GHSA-8x94-hmjh-97hq","Warn: Project is vulnerable to: PYSEC-2016-2 / GHSA-c8c8-9472-w52h","Warn: Project is vulnerable to: PYSEC-2016-3 / GHSA-crhm-qpjc-cm64","Warn: Project is vulnerable to: PYSEC-2014-4 / GHSA-f7cm-ccfp-3q4r","Warn: Project is vulnerable to: PYSEC-2016-16 / GHSA-fp6p-5xvw-m74f","Warn: Project is vulnerable to: PYSEC-2011-8 / GHSA-fwr5-q9rx-294f","Warn: Project is vulnerable to: PYSEC-2015-5 / GHSA-gv98-g628-m9x5","Warn: Project is vulnerable to: PYSEC-2015-20 / GHSA-h582-2pch-3xv3","Warn: Project is vulnerable to: PYSEC-2011-5 / GHSA-h95j-h2rv-qrg4","Warn: Project is vulnerable to: GHSA-hmr4-m2h5-33qx","Warn: Project is vulnerable to: PYSEC-2015-6 / GHSA-jhjg-w2cp-5j44","Warn: Project is vulnerable to: PYSEC-2016-15 / GHSA-pw27-w7w4-9qc7","Warn: Project is vulnerable to: PYSEC-2015-10 / GHSA-q5qw-4364-5hhm","Warn: Project is vulnerable to: PYSEC-2011-4 / GHSA-rm2j-x595-q9cj","Warn: Project is vulnerable to: GHSA-rrqc-c2jx-6jgv","Warn: Project is vulnerable to: PYSEC-2014-1 / GHSA-rvq6-mrpv-m6rm","Warn: Project is vulnerable to: PYSEC-2014-7 / GHSA-rw75-m7gp-92m3","Warn: Project is vulnerable to: PYSEC-2019-16 / GHSA-vfq6-hq5r-27r6","Warn: Project is vulnerable to: PYSEC-2014-3 / GHSA-wqjj-hx84-v449","Warn: Project is vulnerable to: PYSEC-2011-3 / GHSA-wxg3-mfph-qg9w","Warn: Project is vulnerable to: PYSEC-2011-1 / GHSA-x88j-93vc-wpmp","Warn: Project is vulnerable to: PYSEC-2007-1","Warn: Project is vulnerable to: PYSEC-2008-1","Warn: Project is vulnerable to: PYSEC-2008-2","Warn: Project is vulnerable to: PYSEC-2009-3","Warn: Project is vulnerable to: PYSEC-2015-11","Warn: Project is vulnerable to: PYSEC-2015-7","Warn: Project is vulnerable to: PYSEC-2016-18","Warn: Project is vulnerable to: GHSA-xq7p-g2vc-g82p","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-7hpj-7hhx-2fgx","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T08:19:35.874Z","repository_id":7440723,"created_at":"2025-08-17T08:19:35.874Z","updated_at":"2025-08-17T08:19:35.874Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31637748,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","django","django-s3direct","python","s3","storages","uploads"],"created_at":"2024-07-31T15:01:32.166Z","updated_at":"2026-04-10T10:02:35.717Z","avatar_url":"https://github.com/bradleyg.png","language":"Python","funding_links":[],"categories":["Python","JavaScript"],"sub_categories":[],"readme":"# django-s3direct\n\n## Directly upload files to S3 compatible services with Django.\n\n\u003cimg src=\"https://raw.githubusercontent.com/bradleyg/django-s3direct/master/screenshot.png\" width=\"100%\"/\u003e\n\n## Installation\n\nInstall with Pip:  \n`pip install django-s3direct`\n\n## Access setup\n\n### When setting up access credentials you have two options:\n\n### Option 1:\n\n**Generate access credentials and add them directly to your Django settings**.\nIf using Amazon S3 you'll also need to create an IAM policy which grants\npermission to upload to your bucket for your newly created credentials.\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Action\": [\n        \"s3:AbortMultipartUpload\",\n        \"s3:GetObject\",\n        \"s3:ListMultipartUploadParts\",\n        \"s3:PutObject\",\n        \"s3:PutObjectAcl\"\n      ],\n      \"Effect\": \"Allow\",\n      \"Resource\": \"arn:aws:s3:::YOUR_BUCKET_NAME/*\"\n    }\n  ]\n}\n```\n\n### Option 2:\n\n**Use the EC2 instance profile and its attached IAM role (AWS only)**  \nEnsure the following trust policy is in place in addition to the policy\nabove. You'll also need the\n[boto3](https://github.com/boto/boto3) package installed.\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"Service\": \"ec2.amazonaws.com\"\n      },\n      \"Action\": \"sts:AssumeRole\"\n    }\n  ]\n}\n```\n\n### CORS setup\n\nAdd a CORS policy to your bucket. Note the ETag header is\nimportant as it is used for multipart uploads. For more information see\n[here](https://github.com/TTLabs/EvaporateJS/wiki/Configuring-The-AWS-S3-Bucket).\n\n```json\n[\n  {\n    \"AllowedHeaders\": [\"*\"],\n    \"AllowedMethods\": [\"GET\", \"HEAD\", \"PUT\", \"POST\", \"DELETE\"],\n    \"AllowedOrigins\": [\"http://localhost:8080\"],\n    \"ExposeHeaders\": [\"ETag\"],\n    \"MaxAgeSeconds\": 3000\n  }\n]\n```\n\n## Django Setup\n\n### settings.py\n\n```python\nINSTALLED_APPS = [\n    ...\n    's3direct',\n    ...\n]\n\nTEMPLATES = [{\n    ...\n    'APP_DIRS': True,\n    ...\n}]\n\n# AWS\n\n# If these are set to None, the EC2 instance profile and IAM role are used.\nAWS_ACCESS_KEY_ID = 'your-aws-access-key-id'\nAWS_SECRET_ACCESS_KEY = 'your-aws-secret-access-key'\n\n# Bucket name\nAWS_STORAGE_BUCKET_NAME = 'your-aws-s3-bucket-name'\n\n# The region of your bucket, more info:\n# http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\nAWS_S3_REGION_NAME = 'eu-west-1'\n\n# The endpoint of your bucket, more info:\n# http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\nAWS_S3_ENDPOINT_URL = 'https://s3.eu-west-1.amazonaws.com'\n\nS3DIRECT_DESTINATIONS = {\n    'example_destination': {\n        # \"key\" [required] The location to upload file\n        #       1. String: folder path to upload to\n        #       2. Function: generate folder path + filename using a function\n        'key': 'uploads/images',\n\n        # \"auth\" [optional] Limit to specfic Django users\n        #        Function: ACL function\n        'auth': lambda u: u.is_staff,\n\n        # \"allowed\" [optional] Limit to specific mime types\n        #           List: list of mime types\n        'allowed': ['image/jpeg', 'image/png', 'video/mp4'],\n\n        # \"bucket\" [optional] Bucket if different from AWS_STORAGE_BUCKET_NAME\n        #          String: bucket name\n        'bucket': 'custom-bucket',\n\n        # \"endpoint\" [optional] Endpoint if different from AWS_S3_ENDPOINT_URL\n        #            String: endpoint URL\n        'endpoint': 'custom-endpoint',\n\n        # \"region\" [optional] Region if different from AWS_S3_REGION_NAME\n        #          String: region name\n        'region': 'custom-region', # Default is 'AWS_S3_REGION_NAME'\n\n        # \"acl\" [optional] Custom ACL for object, default is 'public-read'\n        #       String: ACL\n        'acl': 'private',\n\n        # \"cache_control\" [optional] Custom cache control header\n        #                 String: header\n        'cache_control': 'max-age=2592000',\n\n        # \"content_disposition\" [optional] Custom content disposition header\n        #                       String: header\n        'content_disposition': lambda x: 'attachment; filename=\"{}\"'.format(x),\n\n        # \"content_length_range\" [optional] Limit file size\n        #                        Tuple: (from, to) in bytes\n        'content_length_range': (5000, 20000000),\n\n        # \"server_side_encryption\" [optional] Use serverside encryption\n        #                          String: encrytion standard\n        'server_side_encryption': 'AES256',\n\n        # \"allow_existence_optimization\" [optional] Checks to see if file already exists,\n        #                                returns the URL to the object if so (no upload)\n        #                                Boolean: True, False\n        'allow_existence_optimization': False,\n    },\n    'example_destination_two': {\n        'key': lambda filename, args: args + '/' + filename,\n    \t'key_args': 'uploads/images',\n    }\n}\n```\n\n### urls.py\n\n```python\nurlpatterns = [\n    ...\n    url(r'^s3direct/', include('s3direct.urls')),\n    ...\n]\n```\n\nRun `python manage.py collectstatic` if required.\n\n## Use in Django admin\n\n### models.py\n\n```python\nfrom django.db import models\nfrom s3direct.fields import S3DirectField\n\nclass Example(models.Model):\n    video = S3DirectField(dest='example_destination')\n```\n\n## Use the widget in a custom form\n\n### forms.py\n\n```python\nfrom django import forms\nfrom s3direct.widgets import S3DirectWidget\n\nclass S3DirectUploadForm(forms.Form):\n    images = forms.URLField(widget=S3DirectWidget(dest='example_destination'))\n```\n\n**\\*Optional.** You can modify the HTML of the widget by overiding template **s3direct/templates/s3direct-widget.tpl**\n\n### views.py\n\n```python\nfrom django.views.generic import FormView\nfrom .forms import S3DirectUploadForm\n\nclass MyView(FormView):\n    template_name = 'form.html'\n    form_class = S3DirectUploadForm\n```\n\n### templates/form.html\n\n```html\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cmeta charset=\"utf-8\" /\u003e\n    \u003ctitle\u003es3direct\u003c/title\u003e\n    {{ form.media }}\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cform action=\"\" method=\"post\"\u003e{% csrf_token %} {{ form.as_p }}\u003c/form\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Examples\n\nExamples of both approaches can be found in the examples folder. To run them:\n\n```shell\n$ git clone git@github.com:bradleyg/django-s3direct.git\n$ cd django-s3direct\n$ python setup.py install\n$ cd example\n\n# Add config to your environment\nexport AWS_ACCESS_KEY_ID='…'\nexport AWS_SECRET_ACCESS_KEY='…'\nexport AWS_STORAGE_BUCKET_NAME='…'\nexport AWS_S3_REGION_NAME='…'\nexport AWS_S3_ENDPOINT_URL='…'\n\n$ python manage.py migrate\n$ python manage.py createsuperuser\n$ python manage.py runserver\n```\n\nVisit `http://localhost:8080/admin` to view the admin widget and\n`http://localhost:8080/form` to view the custom form widget.\n\n## Development\n\n```shell\n$ git clone git@github.com:bradleyg/django-s3direct.git\n$ cd django-s3direct\n\n# Add your AWS keys/details to .env file and export\n$ cp .env-dist .env\n\n# Frontend deps\n$ npm i\n\n# Install locally\n$ python setup.py develop\n\n# Run examples\n$ python example/manage.py migrate\n$ python example/manage.py createsuperuser\n$ python example/manage.py runserver 0.0.0.0:8080\n\n# Run tests\n$ npm run test\n\n# Run frontend bundler and Django server\n$ npm run dev\n\n# Watch and build frontend (dev)\n$ npm run watch\n\n# Build frontend (prod)\n$ npm run build\n\n# Format python // PEP8\n$ npm run yapf\n\n# Upload to PYPI\n$ npm run pypi\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbradleyg%2Fdjango-s3direct","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbradleyg%2Fdjango-s3direct","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbradleyg%2Fdjango-s3direct/lists"}