Permalink
Browse files

v 0.0.1

  • Loading branch information...
elijahr committed May 25, 2012
1 parent d77c7dd commit 6d1ff82aa41594fc4aff111eef6dc3dee1465998
View
@@ -1,4 +1,6 @@
-*.log
-*.pot
-*.pyc
-local_settings.py
+*.py[c|o]
+.DS_Store
+*~
+*.egg-info
+build/*
+dist/*
View
12 LICENSE
@@ -0,0 +1,12 @@
+
+
+django-persistent-file-widget
+Copyright (c) 2012, Elijah Rutschman, Brent Sanders, Scott Meisburger
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
@@ -0,0 +1,2 @@
+include LICENSE README.rst requirements.txt
+recursive-include persistent_widget/templates *
View
@@ -1,4 +0,0 @@
-django-persistent-file-widget
-=============================
-
-A django form file widget that persists between erroneous form submissions!
View
@@ -0,0 +1,15 @@
+=============================
+django-persistent-file-widget
+=============================
+
+A django form file widget that persists between erroneous form submissions!
+
+Usage
+-----
+
+1. Run ``pip install django-persistent-file-widget`` or place ``persistent_widget`` on your Python path.
+
+2. Add ``persistent_widget`` to your list of ``INSTALLED_APPS``.
+
+3. There are two widgets available, ``persistent_widget.widgets.PersistentFileWidget`` and ``persistent_widget.widgets.PersistentImageWidget``. The latter will display a thumbnail if ``sorl.thumbnail`` is installed.
+
No changes.
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
@@ -0,0 +1,8 @@
+
+<input type="hidden" name="{{ name }}-persistent" value="{% firstof existing_path value.name %}" />
+
+{% if thumb_url %}
+ {% load thumbnail %}
+ <a href="{{ image_url }}" target="_blank"><img src="{{ thumb_url }}" /></a><br />
+{% endif %}
+
View
@@ -0,0 +1,16 @@
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
View
@@ -0,0 +1,58 @@
+
+from django.conf import settings
+from django.core.files import File
+
+import os
+
+def get_media_url(path, full=False):
+ "returns the url relative to MEDIA_URL give a path relative to MEDIA_ROOT"
+
+ if path.startswith('http:') or path.startswith('https:'):
+ return path
+
+ path = os.path.abspath(path)
+
+ media_root = os.path.abspath(settings.MEDIA_ROOT)
+ if not media_root.endswith('/'):
+ media_root = media_root + '/'
+
+ media_url = settings.MEDIA_URL
+ if not media_url.endswith('/'):
+ media_url = media_url + '/'
+ return path.replace(media_root, media_url)
+
+
+def get_media_relative_path(path):
+ "returns the path relative to MEDIA_ROOT that this file lives at"
+ media_root = os.path.abspath(settings.MEDIA_ROOT)
+ if not media_root.endswith('/'):
+ media_root = media_root + '/'
+ return path.replace(media_root, '')
+
+
+class MediaFile(File):
+
+ @property
+ def url(self):
+ return get_media_url(self.name)
+
+def make_tmp_media_file(fileobj):
+ """
+ Copies an InMemoryUploadedFile, File, or ContentFile to a file available
+ at MEDIA_URL
+ """
+ i = 0
+ dirname = os.path.join(settings.MEDIA_ROOT, 'tmp')
+ path = os.path.join(dirname, fileobj.name)
+ try:
+ # make the parent directories if they don't exist
+ os.makedirs(os.path.dirname(path))
+ except OSError:
+ pass
+ fileobj.seek(0)
+ contents = fileobj.read()
+ with open(path, 'w+b') as f:
+ f.write(contents)
+ fileobj.seek(0)
+ return MediaFile(open(path, 'r+b'), name=get_media_relative_path(path))
+
@@ -0,0 +1,98 @@
+from django.conf import settings
+from django.contrib.admin.widgets import AdminFileWidget
+from django.core.files.base import ContentFile
+from django.core.files.uploadedfile import InMemoryUploadedFile
+from django.template.loader import render_to_string
+from django.utils.safestring import mark_safe
+from persistent_widget.utils import (get_media_relative_path, get_media_url,
+ make_tmp_media_file)
+
+
+import os
+import mimetypes
+
+
+class PersistentFileWidget(AdminFileWidget):
+ """
+ A django form file widget that persists between erroneous form submissions.
+ """
+
+ template_name = 'persistent_widget/persistent_file_widget.html'
+
+ def __init__(self, *args, **kwargs):
+ self.exists = False
+ self._upload = None
+ super(PersistentFileWidget, self).__init__(*args, **kwargs)
+
+ def render(self, name, value, attrs=None):
+ output = []
+ if value:
+ try:
+ if not self._upload is None:
+ upload = self._upload
+ if not hasattr(value, 'url'):
+ # create a temporary file to contain the in-memory-upload
+ upload = value = make_tmp_media_file(value)
+ self._upload = upload
+ else:
+ upload = value
+ data = self.get_context_data(name=name, value=value,
+ upload=upload, exists=self.exists)
+ output.append(render_to_string(self.template_name, data))
+ except IOError:
+ pass
+ output.append(super(AdminFileWidget, self).render(name, value, attrs))
+ return mark_safe(u''.join(output))
+
+ def get_context_data(self, **data):
+ if self.exists:
+ upload = data['upload']
+ data['existing_path'] = get_media_relative_path(upload.name)
+ return data
+
+ def value_from_datadict(self, data, files, name):
+ self.exists = False
+ if not files is None and name in files:
+ existing_name = '%s-persistent' % name
+ existing = data.get(existing_name)
+ if existing:
+ existing = existing.replace('..', '')
+ path = os.path.join(settings.MEDIA_ROOT, existing)
+ with open(path, 'r+b') as file:
+ contents = file.read()
+ size = file.tell()
+ uploaded_file = InMemoryUploadedFile(
+ file = ContentFile(contents),
+ field_name = name,
+ name = existing,
+ content_type = mimetypes.guess_type(path)[0],
+ size = size,
+ charset = mimetypes.guess_type(path)[1]
+ )
+ files[name] = uploaded_file
+ self.exists = True
+ return super(PersistentFileWidget, self).value_from_datadict(data, files, name)
+
+
+class PersistentImageWidget(PersistentFileWidget):
+ """
+ A django form file widget that persists between erroneous form submissions
+ and displays a thumbnail of images if sorl is installed.
+ """
+ def get_context_data(self, **data):
+ data = super(PersistentImageWidget, self).get_context_data(**data)
+ try:
+ from sorl.thumbnail import get_thumbnail
+ upload = data['upload']
+ thumb = get_thumbnail(upload, '100x100', crop='center',
+ quality=99)
+ thumb_url = (get_media_url(thumb.name)
+ if thumb.url.startswith('http:')
+ or thumb.url.startswith('https:')
+ else get_media_url(thumb.url))
+ image_url = get_media_url(upload.file.name)
+ data.update({ 'image_url': image_url, 'thumb_url': thumb_url })
+ except ImportError:
+ pass
+ return data
+
View
No changes.
View
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+
+from setuptools import setup, find_packages
+
+with open('README.rst') as f:
+ readme = f.read()
+
+with open('LICENSE') as f:
+ license = f.read()
+
+setup(
+ name='django-persistent-file-widget',
+ version='0.0.1',
+ description='A django form file widget that persists between erroneous form submissions!',
+ long_description=readme,
+ author='Elijah Rutschman, Brent Sanders, Scott Meisburger',
+ author_email='info+django-persistent-file-widget@sandersnewmedia.com',
+ url='https://github.com/sandersnewmedia/django-persistent-file-widget',
+ license=license,
+ packages=find_packages(exclude=('tests',)),
+ package_data={ 'persistent_widget': [ 'templates/persistent_widget/*' ] }
+)

0 comments on commit 6d1ff82

Please sign in to comment.