{"id":37078183,"url":"https://github.com/thorgate/django-upthor","last_synced_at":"2026-01-14T09:04:08.715Z","repository":{"id":57422500,"uuid":"21239776","full_name":"thorgate/django-upthor","owner":"thorgate","description":"`django-upthor` provides a django application for simple ajax file uploads.","archived":true,"fork":false,"pushed_at":"2017-09-01T11:36:21.000Z","size":432,"stargazers_count":6,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-12-10T13:31:32.776Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thorgate.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-06-26T12:25:15.000Z","updated_at":"2023-01-28T17:36:42.000Z","dependencies_parsed_at":"2022-09-13T02:24:42.834Z","dependency_job_id":null,"html_url":"https://github.com/thorgate/django-upthor","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/thorgate/django-upthor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorgate%2Fdjango-upthor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorgate%2Fdjango-upthor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorgate%2Fdjango-upthor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorgate%2Fdjango-upthor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thorgate","download_url":"https://codeload.github.com/thorgate/django-upthor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorgate%2Fdjango-upthor/sbom","scorecard":{"id":882879,"data":{"date":"2025-08-11","repo":{"name":"github.com/thorgate/django-upthor","commit":"e2a2e6bac067693ea89a5f3409ca5e8f7419d5e2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","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":"Code-Review","score":2,"reason":"Found 4/14 approved changesets -- score normalized to 2","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":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"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":"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":-1,"reason":"No tokens found","details":null,"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":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"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: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE: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":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2018-97 / GHSA-6528-wvf6-f6qg","Warn: Project is vulnerable to: PYSEC-2017-94 / GHSA-cq27-v7xp-c356"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 20 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"}}]},"last_synced_at":"2025-08-24T08:53:47.106Z","repository_id":57422500,"created_at":"2025-08-24T08:53:47.106Z","updated_at":"2025-08-24T08:53:47.106Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28414738,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:38:59.149Z","status":"ssl_error","status_checked_at":"2026-01-14T08:38:43.588Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":[],"created_at":"2026-01-14T09:04:08.232Z","updated_at":"2026-01-14T09:04:08.710Z","avatar_url":"https://github.com/thorgate.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n#django-upthor\n\n[![PyPI version](https://badge.fury.io/py/django-upthor.svg)](https://badge.fury.io/py/django-upthor) \n[![Build Status](https://travis-ci.org/thorgate/django-upthor.svg?branch=master)](https://travis-ci.org/thorgate/django-upthor)\n\n`django-upthor` provides a django application for simple ajax file uploads. We use\nhttps://github.com/blueimp/jQuery-File-Upload for the upload functionality.\n\n**Warning:** This isn't close to being a complete app, but it's getting there.\n\n\n#Usage\n\n\n##Step 1. Install\n\n- `pip install django-upthor`\n\nNow you have two options:\n\n- If you want to encrypt FQ values, install pycrypto. `pip install pycrypto==2.6.1`\n- Or you can, disable FQ encryption by adding `THOR_DISABLE_FQ_ENCRYPT = True` to your settings file.\n\n\n\n##Step 2. (Django 1.6+)\nAdd 'upthor' to your installed apps in settings.py:\n\n```\nINSTALLED_APPS = (\n    ...\n    \"upthor\",\n)\n```\n\nThen:\n\n```\npython manage.py migrate\n```\n\n\n##Step 3. Use it in your app's models.\n\n```\n\nimport os\nimport uuid\n\nfrom django.db import models\nfrom upthor import fields as thor_fields\n\n\ndef random_upload_path(instance, filename):\n    # Split the uuid into two parts so that we won't run into subdirectory count limits. First part has 3 hex chars,\n    #  thus 4k possible values.\n    uuid_hex = uuid.uuid4().hex\n    return os.path.join(uuid_hex[:3], uuid_hex[3:], filename)\n\n\ndef post_example_file_link(real_instance, temporary_instance, raw_file):\n    \"\"\"\n        A callback called after linking the temporary file with the model.\n\n        **Warning**: Don't call instances save method from here, cause it will cause an recursion error.\n\n        @:param real_instance An instance of the model the file is attached to\n        @:param temporary_instance An instance of TemporaryFileWrapper that the form links to.\n        @:param raw_file The raw file that is being uploaded.\n\n        @:return bool If True, the uploaded temporary file is removed once the linking is complete.\n    \"\"\"\n    return True\n\n\ndef get_file_image(file_path):\n    \"\"\" An optional function that returns the display image html for files after uploading is complete\"\"\"\n\n    return '\u003ci class=\"fa fa-file\"\u003e\u003c/i\u003e'\n\n\nclass ExampleModelWithFile(models.Model):\n    name = models.CharField(max_length=50)\n    file = thor_fields.ThorFileField(upload_to=random_upload_path,\n                                   allowed_types=['*'], widget=thor_fields.ThorSingleUploadWidget,\n                                   post_link=post_product_file_link,\n                                   get_upload_image=get_file_image)\n```\n\n\n##Step 4. Make sure to include form media.\n\nMake sure you include the media files for the form in your templates:\n\nE.g. Add the following codes where form is the context\nobject of your modelform that uses the uploader fields.\n\n```\n    {{ form.media.css }}\n\n    {{ form.media.js }}\n```\n\n\n##Step 5. Add the upload url to your project urls.\n\n```\n    url(r'', include('upthor.urls')),\n```\n\n\n##Step 6. Optional stuff\n\n#### Temporary file cleanup\n\nIf you want to clean up temporary files automatically, you'll need to install [django-cron](https://github.com/Tivix/django-cron) and add `upthor.cron.CleanTemporaryFiles` to your cron classes in settings.\n\nAlternatively to clean up manually you can use the management command `clean_temporary_files`.\n\n#### Custom upload widget template\n\nYou can override `ThorSingleUploadWidget.render_template` to return your own widget template instead of the [hardcoded one defined in widgets.py](upthor/widgets.py). Although the structure (including most classes) has to remain the same, there are a few data attributes on `.file-upload` that you can use to customize behavior:\n\n| Data Attribute Name | Type    | Description                              |\n| ------------------- | ------- | ---------------------------------------- |\n| upload-url          | string  | **Required:** URL to POST temporary files to, defaults to reverse of `thor-file-upload`. |\n| max-size            | number  | **Required:** Maximum allowed file size in bytes, defaults to `THOR_MAX_FILE_SIZE`. |\n| size-error          | string  | **Required:** Text to display if the file doesn't meet the size requirements, defaults to ` \"Uploaded file too large\"`. |\n| use-background      | boolean | Whether or not to use `background-image` instead of `img` elements, defaults to false. |\n\n\n#Backends\n\nCurrently it only supports local file backend, but we plan to add other backends when we reach a stable state.\n\n\n#Settings\n\nThe following settings are customizable using your django project settings file.\n\n**THOR_UPLOAD_TO**\n\nPath where the upload files will be stored. Defaults to \"temp-files\".\n\n**THOR_EXPIRE_TIME**\n\nHow long to keep temporary files in the database and on disk. Defaults to \"60*60*24\", e.g. 24 hours.\n\n**THOR_LINKED_EXPIRE_TIME**\n\nHow long to keep linked temporary files in the database and on disk. Defaults to \"60*60*6\", e.g. 6 hours.\n\n**THOR_MAX_FILE_SIZE**\n\nThe max file size of uploaded files. Defaults to \"2*1024*1024\", e.g. 2 MB.\n\n**THOR_DISABLE_FQ_ENCRYPT**\n\nDisable the FQ Encryption, if this is False you need to install pycrypto since that is used for encryption. Defaults to \"False\".\n\n**THOR_ENABLE_ADMIN**\n\nShould TemporaryFileWrapper model be shown in the admin interface. Defaults to \"True\".\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthorgate%2Fdjango-upthor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthorgate%2Fdjango-upthor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthorgate%2Fdjango-upthor/lists"}