├── MANIFEST.in ├── README.rst ├── kittenstorage ├── __init__.py ├── settings.py └── storages │ ├── ColorKitten.py │ ├── GreyKitten.py │ └── __init__.py └── setup.py /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | django-kittenstorage 3 | ==================== 4 | kittenstorage is a so called *development storage engine*. 5 | 6 | Many people have the problem with gigantomanic production databases with 7 | gigabytes of pictures/files. It is a pain to keep the image files synchronised 8 | between development and production environments. 9 | 10 | Therefore I have written this storage engine. In case a file is not found, 11 | an image from placekitten.com_ will be used/displayed 12 | instead. 13 | 14 | If you are sick of kittens, you might want to check out django-dogstorage_ or django-apestorage_. 15 | 16 | sorl-thumbnail users 17 | ==================== 18 | 19 | Note that newer versions of sorl-thumbnail have an integrated dummy engine, which 20 | can load images from various dummy sources. This is super cool and I highly recommend 21 | this over kittenstorage. Go and have a look at THUMBNAIL_DUMMY_. 22 | 23 | The setting for placeholder kittens source would be: 24 | 25 | ``THUMBNAIL_DUMMY_SOURCE = http://placekitten.com/%(width)s/%(height)s`` 26 | 27 | or if you prefer grayscale: 28 | 29 | ``THUMBNAIL_DUMMY_SOURCE = http://placekitten.com/g/%(width)s/%(height)s`` 30 | 31 | Setup 32 | ===== 33 | It's on pypi. 34 | 35 | ``pip install django-kittenstorage`` 36 | 37 | Feel free to clone from github too. Forking is welcome as well :-) 38 | 39 | In your django settings file: 40 | 41 | ``DEFAULT_FILE_STORAGE = 'kittenstorage.storages.GreyKitten'`` 42 | 43 | Storage Engines 44 | =============== 45 | kittenstorage offers two engines: 46 | 47 | 1. ``kittenstorage.storages.GreyKitten`` 48 | 2. ``kittenstorage.storages.ColorKitten`` 49 | 50 | Choose depending on the saturation you want. I prefer ``GreyKitten`` since it 51 | does have a pretty classy look. 52 | 53 | Settings 54 | ======== 55 | There is only one setting: 56 | 57 | KITTEN_SIZE 58 | Default: ``(1024, 1024)`` 59 | 60 | A tuple of format `(width, height)`, specifiying the size of the image 61 | requested from placekitten__. 62 | 63 | 64 | .. _django-dogstorage: https://github.com/originell/django-dogstorage/ 65 | .. _django-apestorage: https://github.com/originell/django-apestorage/ 66 | .. _THUMBNAIL_DUMMY: http://sorl-thumbnail.readthedocs.org/en/latest/reference/settings.html#thumbnail-dummy 67 | .. _placekitten.com: http://placekitten.com/ 68 | __ placekitten.com_ 69 | 70 | -------------------------------------------------------------------------------- /kittenstorage/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/originell/django-kittenstorage/3a8575ce91cfc0129e454b62c5e8e8bfcce0df02/kittenstorage/__init__.py -------------------------------------------------------------------------------- /kittenstorage/settings.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | 3 | KITTEN_SIZE = getattr(settings, 'KITTEN_SIZE', (1024, 1024)) 4 | -------------------------------------------------------------------------------- /kittenstorage/storages/ColorKitten.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | import urllib2 3 | 4 | from django.core.cache import cache 5 | from django.core.files import File 6 | from django.core.files.storage import FileSystemStorage 7 | 8 | from kittenstorage.settings import KITTEN_SIZE 9 | 10 | 11 | class ColorKitten(FileSystemStorage): 12 | """ 13 | If a file is not found on disk, return a kitten picture. 14 | """ 15 | def _open(self, name, mode='rb'): 16 | if not self.exists(name): 17 | kittenz = cache.get('kittenz', False) 18 | if not kittenz: 19 | # Grab a kitten from placekitten. 20 | response = urllib2.urlopen('http://placekitten.com/%s/%s' 21 | % (KITTEN_SIZE[0], KITTEN_SIZE[1])) 22 | kitten_img = response.read() 23 | cache.set('kittenz', kitten_img) 24 | kitten = tempfile.TemporaryFile() 25 | kitten.write(kitten_img) 26 | # .write places the readhead at the end. Resetting it 27 | # to the start, otherwise an empty File() will be created. 28 | kitten.seek(0) 29 | return File(kitten) 30 | else: 31 | past_kitten = tempfile.TemporaryFile() 32 | past_kitten.write(kittenz) 33 | past_kitten.seek(0) 34 | return File(past_kitten) 35 | return super(ColorKitten, self)._open(name, mode) 36 | 37 | -------------------------------------------------------------------------------- /kittenstorage/storages/GreyKitten.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | import urllib2 3 | 4 | from django.core.cache import cache 5 | from django.core.files import File 6 | from django.core.files.storage import FileSystemStorage 7 | 8 | from kittenstorage.settings import KITTEN_SIZE 9 | 10 | 11 | class GreyKitten(FileSystemStorage): 12 | """ 13 | If a file is not found on disk, return a greyscale kitten picture. 14 | """ 15 | def _open(self, name, mode='rb'): 16 | if not self.exists(name): 17 | kittenz = cache.get('kittenz', False) 18 | if not kittenz: 19 | # Grab a kitten from placekitten. 20 | # /g/ means grayscale 21 | response = urllib2.urlopen('http://placekitten.com/g/%s/%s' 22 | % (KITTEN_SIZE[0], KITTEN_SIZE[1])) 23 | kitten_img = response.read() 24 | cache.set('kittenz', kitten_img) 25 | kitten = tempfile.TemporaryFile() 26 | kitten.write(kitten_img) 27 | # .write places the readhead at the end. Resetting it 28 | # to the start, otherwise an empty File() will be created. 29 | kitten.seek(0) 30 | return File(kitten) 31 | else: 32 | past_kitten = tempfile.TemporaryFile() 33 | past_kitten.write(kittenz) 34 | past_kitten.seek(0) 35 | return File(past_kitten) 36 | return super(GreyKitten, self)._open(name, mode) 37 | 38 | -------------------------------------------------------------------------------- /kittenstorage/storages/__init__.py: -------------------------------------------------------------------------------- 1 | from kittenstorage.storages.ColorKitten import ColorKitten 2 | from kittenstorage.storages.GreyKitten import GreyKitten 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from setuptools import find_packages 3 | 4 | setup( 5 | name='django-kittenstorage', 6 | version='1.0.0', 7 | url='https://github.com/originell/django-kittenstorage', 8 | author='Luis Nell', 9 | author_email='cooperate@originell.org', 10 | packages=find_packages(), 11 | platforms='any', 12 | description=('Django Storage Engine which returns images of kittens if ' 13 | 'files could not be found.'), 14 | long_description=open('README.rst').read(), 15 | classifiers=[ 16 | "Development Status :: 5 - Production/Stable", 17 | "Environment :: Web Environment", 18 | "Framework :: Django", 19 | "Intended Audience :: Developers", 20 | "License :: OSI Approved :: BSD License", 21 | "Operating System :: OS Independent", 22 | "Programming Language :: Python", 23 | "Topic :: Internet :: WWW/HTTP :: Dynamic Content", 24 | "Topic :: Multimedia :: Graphics", 25 | ], 26 | ) 27 | 28 | --------------------------------------------------------------------------------