{ "info": { "author": "Arthur Street", "author_email": "arthur@racingtadpole.com", "bugtrack_url": null, "classifiers": [ "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content" ], "description": "=====\ndjango-private-media\n=====\n\nOverview\n--------\nBy default, Django lets you specify a MEDIA_ROOT where your user (or admin)-uploaded media is placed. It is accessible to all at the MEDIA_URL.\n\nUsing django-private-media, you can also specify a PRIVATE_MEDIA_ROOT and PRIVATE_MEDIA_URL. Private files or images are uploaded using the provided PrivateMediaStorage() storage class. They are served by a view which checks the user's authorization before serving them.\n\nCurrently there are only two options for serving them, a default server useful for development, and Apache's XSendFile. Setting up XSendFile at Webfaction (for example) is covered `here `_. By adapting code from Stephan Foulis's django-filer it would be easy to add an nginx server.\n\nMotivation\n----------\nI have long wanted the capability for user uploads to be private, but couldn't find a guide to set it up. When I looked into django-filer's approach to secure file downloads I finally understood how it could be done; however, I have an existing project and do not want to adopt the full functionality of django-filer.\n\nI also wanted to be able to apply it to existing projects without any data migrations; with it, you only need to make sure your media files are relocated from the MEDIA_ROOT to the PRIVATE_MEDIA_ROOT.\n\nAttribution\n-----------\nKey parts of this code are based on code by Stephan Foulis and contributors from \n`django-filer `_.\n\nCaveats\n-------\nAlthough it works satisfactorily for my purposes so far, this is not a finished project. In particular, it does not have any tests. Yet.\n\nRequirements\n--------------\nDjango 1.5 or later.\n\nQuick start\n-----------\nTo upload to a private location, add to your `settings.py` e.g.::\n\n PRIVATE_MEDIA_URL = '/private/'\n if DEBUG:\n # dev\n import os\n PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))\n PRIVATE_MEDIA_ROOT = os.path.join(PROJECT_PATH, 'private')\n PRIVATE_MEDIA_SERVER = 'private_media.servers.DefaultServer'\n else:\n # prod\n PRIVATE_MEDIA_ROOT = '/home/user/my/path/to/private/media'\n PRIVATE_MEDIA_SERVER = 'private_media.servers.ApacheXSendfileServer'\n #PRIVATE_MEDIA_SERVER_OPTIONS = {'arg1': 1, ...} # (optional) kwargs to init server\n\nThe default permissioning is for authenticated staff members to see all, and no one else.\nTo generalise this, also add::\n\n PRIVATE_MEDIA_PERMISSIONS = 'myapp.permissions.MyPermissionClass'\n PRIVATE_MEDIA_PERMISSIONS_OPTIONS = {'arg1': 1, ...} # (optional) kwargs to init\n\nThis permissions class must have the method::\n\n has_read_permission(self, request, path)\n\nwhich returns True or False.\n\n\nAdd to your `INSTALLED_APPS`::\n\n INSTALLED_APPS = {\n ...\n 'private_media',\n ...\n }\n\n\nAdd to `urls.py`::\n\n ...\n url(r'^', include('private_media.urls')),\n\n\nIn your `models.py`, to upload a specific file or image to a private area, use::\n\n from django.db import models\n from private_media.storages import PrivateMediaStorage\n\n class Car(models.Model):\n photo = models.ImageField(storage=PrivateMediaStorage())\n\n\nBecause the only information about the file available to the permissions method\nis its path, you will need to encode the allowed permissioning into the path on upload.\n\nE.g. you could use this to save the owner's primary key into the path::\n\n import os\n from django.db import models\n from django.contrib.auth.models import User\n from private_media.storages import PrivateMediaStorage\n\n def owner_file_name(instance, filename):\n return os.path.join('cars', \"{0}\".format(instance.user.pk), filename)\n\n class Car(models.Model):\n owner = models.ForeignKey(User)\n photo = models.ImageField(storage=PrivateMediaStorage(), upload_to=owner_file_name)\n\nAnd then provide a permissioning class like this (which lets staff and the owner see it)::\n\n import os\n from django.http import Http404\n\n class OwnerPkPermissions(object):\n def has_read_permission(self, request, path):\n user = request.user\n if not user.is_authenticated():\n return False\n elif user.is_superuser:\n return True\n elif user.is_staff:\n return True\n else:\n try:\n owner_pk = int(os.path.split(os.path.split(path)[0])[1])\n except ValueError:\n raise Http404('File not found')\n return (user.pk==owner_pk)\n\nDetailed documentation is provided at ``_ and in the \"docs\" directory (pending).", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/RacingTadpole/django-private-media", "keywords": "private media xsendfile", "license": "BSD License", "maintainer": null, "maintainer_email": null, "name": "django-private-media", "package_url": "https://pypi.org/project/django-private-media/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/django-private-media/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/RacingTadpole/django-private-media" }, "release_url": "https://pypi.org/project/django-private-media/0.1.3/", "requires_dist": null, "requires_python": null, "summary": "Private media for Django. Check the user's authorization before serving files at PRIVATE_MEDIA_URL, uploaded to PRIVATE_MEDIA_ROOT. Requires Django 1.5.", "version": "0.1.3" }, "last_serial": 1178942, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "4b789e3673cc0468c960ead7f003f0d6", "sha256": "46a4879a7af25f371c50778677a5cac692b309d845ba3afd0609e304453fa13d" }, "downloads": -1, "filename": "django-private-media-0.1.0.macosx-10.7-intel.exe", "has_sig": false, "md5_digest": "4b789e3673cc0468c960ead7f003f0d6", "packagetype": "bdist_wininst", "python_version": "any", "requires_python": null, "size": 75099, "upload_time": "2013-08-14T23:22:42", "url": "https://files.pythonhosted.org/packages/42/db/e1fd8e35cb5c4e50fcb26ae353670a775ba5615beca3a7591c6701cea7a6/django-private-media-0.1.0.macosx-10.7-intel.exe" }, { "comment_text": "", "digests": { "md5": "113b2eac224bae2be27f568cd3f3e8d3", "sha256": "ec6011da505bdd27015ac86f44365682ef23769fbec2dd2a1d77eeb2283946a2" }, "downloads": -1, "filename": "django-private-media-0.1.0.tar.gz", "has_sig": false, "md5_digest": "113b2eac224bae2be27f568cd3f3e8d3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6537, "upload_time": "2013-08-14T23:22:39", "url": "https://files.pythonhosted.org/packages/9c/27/649fa846f0fae5bf22c9e2b780abce2d85a0d30386b55dda8bed0c288787/django-private-media-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "1fa664ab103ae734464c5f5e7d9c7837", "sha256": "5508cb640d4231c16bd4779786bbffd451b760d765a30710a05feeb5802528bc" }, "downloads": -1, "filename": "django-private-media-0.1.1.macosx-10.8-intel.exe", "has_sig": false, "md5_digest": "1fa664ab103ae734464c5f5e7d9c7837", "packagetype": "bdist_wininst", "python_version": "any", "requires_python": null, "size": 75065, "upload_time": "2013-08-24T12:10:40", "url": "https://files.pythonhosted.org/packages/88/43/5dd762896e8df4d7ba25e8849b5299bcdb4b865ac5d4e3b729fb9c8fc828/django-private-media-0.1.1.macosx-10.8-intel.exe" }, { "comment_text": "", "digests": { "md5": "805098b06ff0513a44bec8c02f02069a", "sha256": "ca61f7b1986fdefac72e0cd8b5019bc2761aa5a708af3524c26d37561307ccfd" }, "downloads": -1, "filename": "django-private-media-0.1.1.tar.gz", "has_sig": false, "md5_digest": "805098b06ff0513a44bec8c02f02069a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6534, "upload_time": "2013-08-24T12:10:37", "url": "https://files.pythonhosted.org/packages/8f/10/d5d7c62f52f37c1b2b2154511313cb1db7b361a47c7a66c4a16a8c41e509/django-private-media-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "0df8106f4ecb8a96067700564b107ec5", "sha256": "f36512dd6af9ee773b30b46b85375b7dfcb7ea3da18945459f8dfa4dd354ce3d" }, "downloads": -1, "filename": "django-private-media-0.1.2.macosx-10.8-intel.exe", "has_sig": false, "md5_digest": "0df8106f4ecb8a96067700564b107ec5", "packagetype": "bdist_wininst", "python_version": "any", "requires_python": null, "size": 75072, "upload_time": "2013-11-19T10:44:36", "url": "https://files.pythonhosted.org/packages/97/93/c982bbdbfae8e14eca60e43934b36178385dceae09cb1d25c5f59c086680/django-private-media-0.1.2.macosx-10.8-intel.exe" }, { "comment_text": "", "digests": { "md5": "efd460605dce7c09844e6387135348a9", "sha256": "07e1a1b79a20f294d27b7cbf46db046fa88eb975ad4313bf395bc1477455b363" }, "downloads": -1, "filename": "django-private-media-0.1.2.tar.gz", "has_sig": false, "md5_digest": "efd460605dce7c09844e6387135348a9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6592, "upload_time": "2013-11-19T10:44:33", "url": "https://files.pythonhosted.org/packages/32/e0/1c02351534726a7cf6bcae50038668a3d08a19a4f320cdd0c1c344cc6070/django-private-media-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "3e5bc6629c2526781451be8415b92bbe", "sha256": "1706bee3bb6e554e72cec44a4e2122475694e848ff4cf595ad40bd4b2fea9f0f" }, "downloads": -1, "filename": "django-private-media-0.1.3.macosx-10.8-intel.exe", "has_sig": false, "md5_digest": "3e5bc6629c2526781451be8415b92bbe", "packagetype": "bdist_wininst", "python_version": "any", "requires_python": null, "size": 75123, "upload_time": "2014-08-04T04:44:11", "url": "https://files.pythonhosted.org/packages/ed/56/500166974ff369764cdfa48177e937df965f50f51200cb40aabd939ea2b7/django-private-media-0.1.3.macosx-10.8-intel.exe" }, { "comment_text": "", "digests": { "md5": "595bde11387105c669a77722b6e560ee", "sha256": "9e26544d9e5a023c31cb6da9d0086605233a7d030e6bace93457fb0955aa5a40" }, "downloads": -1, "filename": "django-private-media-0.1.3.tar.gz", "has_sig": false, "md5_digest": "595bde11387105c669a77722b6e560ee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6654, "upload_time": "2014-08-04T04:44:07", "url": "https://files.pythonhosted.org/packages/80/d3/25e199a20f305f8d5a9f3eb8b073f90b05f6e2e74dc24f9e198e11bbb7d4/django-private-media-0.1.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "3e5bc6629c2526781451be8415b92bbe", "sha256": "1706bee3bb6e554e72cec44a4e2122475694e848ff4cf595ad40bd4b2fea9f0f" }, "downloads": -1, "filename": "django-private-media-0.1.3.macosx-10.8-intel.exe", "has_sig": false, "md5_digest": "3e5bc6629c2526781451be8415b92bbe", "packagetype": "bdist_wininst", "python_version": "any", "requires_python": null, "size": 75123, "upload_time": "2014-08-04T04:44:11", "url": "https://files.pythonhosted.org/packages/ed/56/500166974ff369764cdfa48177e937df965f50f51200cb40aabd939ea2b7/django-private-media-0.1.3.macosx-10.8-intel.exe" }, { "comment_text": "", "digests": { "md5": "595bde11387105c669a77722b6e560ee", "sha256": "9e26544d9e5a023c31cb6da9d0086605233a7d030e6bace93457fb0955aa5a40" }, "downloads": -1, "filename": "django-private-media-0.1.3.tar.gz", "has_sig": false, "md5_digest": "595bde11387105c669a77722b6e560ee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6654, "upload_time": "2014-08-04T04:44:07", "url": "https://files.pythonhosted.org/packages/80/d3/25e199a20f305f8d5a9f3eb8b073f90b05f6e2e74dc24f9e198e11bbb7d4/django-private-media-0.1.3.tar.gz" } ] }