| 1 | """ |
|---|
| 2 | Details about AutoOneToOneField: |
|---|
| 3 | http://softwaremaniacs.org/blog/2007/03/07/auto-one-to-one-field/ |
|---|
| 4 | """ |
|---|
| 5 | try: |
|---|
| 6 | from cStringIO import StringIO |
|---|
| 7 | except ImportError: |
|---|
| 8 | from StringIO import StringIO |
|---|
| 9 | import random |
|---|
| 10 | from hashlib import sha1 |
|---|
| 11 | |
|---|
| 12 | from django.db.models import OneToOneField |
|---|
| 13 | from django.db.models.fields.related import SingleRelatedObjectDescriptor |
|---|
| 14 | from django.db import models |
|---|
| 15 | from django.core.files.uploadedfile import SimpleUploadedFile |
|---|
| 16 | from django.core.serializers.json import DjangoJSONEncoder |
|---|
| 17 | from django.utils import simplejson as json |
|---|
| 18 | from django.conf import settings |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | class AutoSingleRelatedObjectDescriptor(SingleRelatedObjectDescriptor): |
|---|
| 22 | def __get__(self, instance, instance_type=None): |
|---|
| 23 | try: |
|---|
| 24 | return super(AutoSingleRelatedObjectDescriptor, self).__get__(instance, instance_type) |
|---|
| 25 | except self.related.model.DoesNotExist: |
|---|
| 26 | obj = self.related.model(**{self.related.field.name: instance}) |
|---|
| 27 | obj.save() |
|---|
| 28 | return obj |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | class AutoOneToOneField(OneToOneField): |
|---|
| 32 | """ |
|---|
| 33 | OneToOneField creates dependent object on first request from parent object |
|---|
| 34 | if dependent oject has not created yet. |
|---|
| 35 | """ |
|---|
| 36 | |
|---|
| 37 | def contribute_to_related_class(self, cls, related): |
|---|
| 38 | setattr(cls, related.get_accessor_name(), AutoSingleRelatedObjectDescriptor(related)) |
|---|
| 39 | #if not cls._meta.one_to_one_field: |
|---|
| 40 | # cls._meta.one_to_one_field = self |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | class ExtendedImageField(models.ImageField): |
|---|
| 44 | """ |
|---|
| 45 | Extended ImageField that can resize image before saving it. |
|---|
| 46 | """ |
|---|
| 47 | |
|---|
| 48 | def __init__(self, *args, **kwargs): |
|---|
| 49 | self.width = kwargs.pop('width', None) |
|---|
| 50 | self.height = kwargs.pop('height', None) |
|---|
| 51 | super(ExtendedImageField, self).__init__(*args, **kwargs) |
|---|
| 52 | |
|---|
| 53 | def save_form_data(self, instance, data): |
|---|
| 54 | if data and self.width and self.height: |
|---|
| 55 | content = self.resize_image(data.read(), width=self.width, height=self.height) |
|---|
| 56 | salt = sha1(str(random.random())).hexdigest()[:5] |
|---|
| 57 | fname = sha1(salt + settings.SECRET_KEY).hexdigest() + '.png' |
|---|
| 58 | data = SimpleUploadedFile(fname, content, data.content_type) |
|---|
| 59 | super(ExtendedImageField, self).save_form_data(instance, data) |
|---|
| 60 | |
|---|
| 61 | def resize_image(self, rawdata, width, height): |
|---|
| 62 | """ |
|---|
| 63 | Resize image to fit it into (width, height) box. |
|---|
| 64 | """ |
|---|
| 65 | try: |
|---|
| 66 | import Image |
|---|
| 67 | except ImportError: |
|---|
| 68 | from PIL import Image |
|---|
| 69 | image = Image.open(StringIO(rawdata)) |
|---|
| 70 | oldw, oldh = image.size |
|---|
| 71 | if oldw >= oldh: |
|---|
| 72 | x = int(round((oldw - oldh) / 2.0)) |
|---|
| 73 | image = image.crop((x, 0, (x + oldh) - 1, oldh - 1)) |
|---|
| 74 | else: |
|---|
| 75 | y = int(round((oldh - oldw) / 2.0)) |
|---|
| 76 | image = image.crop((0, y, oldw - 1, (y + oldw) - 1)) |
|---|
| 77 | image = image.resize((width, height), resample=Image.ANTIALIAS) |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | string = StringIO() |
|---|
| 81 | image.save(string, format='PNG') |
|---|
| 82 | return string.getvalue() |
|---|
| 83 | |
|---|
| 84 | |
|---|
| 85 | class JSONField(models.TextField): |
|---|
| 86 | """ |
|---|
| 87 | JSONField is a generic textfield that neatly serializes/unserializes |
|---|
| 88 | JSON objects seamlessly. |
|---|
| 89 | Django snippet #1478 |
|---|
| 90 | """ |
|---|
| 91 | |
|---|
| 92 | __metaclass__ = models.SubfieldBase |
|---|
| 93 | |
|---|
| 94 | def to_python(self, value): |
|---|
| 95 | if value == "": |
|---|
| 96 | return None |
|---|
| 97 | |
|---|
| 98 | try: |
|---|
| 99 | if isinstance(value, basestring): |
|---|
| 100 | return json.loads(value) |
|---|
| 101 | except ValueError: |
|---|
| 102 | pass |
|---|
| 103 | return value |
|---|
| 104 | |
|---|
| 105 | def get_prep_value(self, value): |
|---|
| 106 | if value == "": |
|---|
| 107 | return None |
|---|
| 108 | if isinstance(value, dict): |
|---|
| 109 | value = json.dumps(value, cls=DjangoJSONEncoder) |
|---|
| 110 | return super(JSONField, self).get_prep_value(value) |
|---|