2009-01-05 14:30:08 +02:00
"""
Details about AutoOneToOneField :
http : / / softwaremaniacs . org / blog / 2007 / 03 / 07 / auto - one - to - one - field /
"""
2009-06-30 12:12:43 +03:00
try :
from cStringIO import StringIO
except ImportError :
from StringIO import StringIO
2009-12-24 13:33:36 +02:00
import random
2012-04-23 14:28:40 +03:00
from hashlib import sha1
2009-01-05 14:30:08 +02:00
from django . db . models import OneToOneField
from django . db . models . fields . related import SingleRelatedObjectDescriptor
2014-05-05 11:03:30 -04:00
from django . db import models , IntegrityError
2009-01-05 14:30:08 +02:00
from django . core . files . uploadedfile import SimpleUploadedFile
2009-10-22 15:19:26 +03:00
from django . core . serializers . json import DjangoJSONEncoder
from django . utils import simplejson as json
2009-12-24 13:33:36 +02:00
from django . conf import settings
2009-01-05 14:30:08 +02:00
2014-04-22 18:41:24 -04:00
import logging
logger = logging . getLogger ( __name__ )
2009-01-05 14:30:08 +02:00
class AutoSingleRelatedObjectDescriptor ( SingleRelatedObjectDescriptor ) :
def __get__ ( self , instance , instance_type = None ) :
try :
return super ( AutoSingleRelatedObjectDescriptor , self ) . __get__ ( instance , instance_type )
except self . related . model . DoesNotExist :
obj = self . related . model ( * * { self . related . field . name : instance } )
2014-04-22 18:41:24 -04:00
try :
obj . save ( )
except IntegrityError :
# Sometimes this happens, try again
try :
return super ( AutoSingleRelatedObjectDescriptor , self ) . __get__ ( instance , instance_type )
except self . related . model . DoesNotExist :
# Doesn't exist but already exists, what the heck.
2014-12-01 15:05:29 -05:00
# logger.warn("Integrity error encountered after DoesNotExist?", extra={'stack': True})
pass
2009-01-05 14:30:08 +02:00
return obj
class AutoOneToOneField ( OneToOneField ) :
"""
OneToOneField creates dependent object on first request from parent object
if dependent oject has not created yet .
"""
def contribute_to_related_class ( self , cls , related ) :
setattr ( cls , related . get_accessor_name ( ) , AutoSingleRelatedObjectDescriptor ( related ) )
#if not cls._meta.one_to_one_field:
# cls._meta.one_to_one_field = self
class ExtendedImageField ( models . ImageField ) :
"""
Extended ImageField that can resize image before saving it .
"""
def __init__ ( self , * args , * * kwargs ) :
self . width = kwargs . pop ( ' width ' , None )
self . height = kwargs . pop ( ' height ' , None )
super ( ExtendedImageField , self ) . __init__ ( * args , * * kwargs )
def save_form_data ( self , instance , data ) :
if data and self . width and self . height :
content = self . resize_image ( data . read ( ) , width = self . width , height = self . height )
2012-04-23 14:28:40 +03:00
salt = sha1 ( str ( random . random ( ) ) ) . hexdigest ( ) [ : 5 ]
fname = sha1 ( salt + settings . SECRET_KEY ) . hexdigest ( ) + ' .png '
2012-05-16 13:05:54 +03:00
data = SimpleUploadedFile ( fname , content , content_type = ' image/png ' )
2009-01-05 14:30:08 +02:00
super ( ExtendedImageField , self ) . save_form_data ( instance , data )
def resize_image ( self , rawdata , width , height ) :
"""
Resize image to fit it into ( width , height ) box .
"""
try :
import Image
except ImportError :
from PIL import Image
image = Image . open ( StringIO ( rawdata ) )
2009-12-24 13:33:36 +02:00
oldw , oldh = image . size
if oldw > = oldh :
x = int ( round ( ( oldw - oldh ) / 2.0 ) )
image = image . crop ( ( x , 0 , ( x + oldh ) - 1 , oldh - 1 ) )
else :
y = int ( round ( ( oldh - oldw ) / 2.0 ) )
image = image . crop ( ( 0 , y , oldw - 1 , ( y + oldw ) - 1 ) )
image = image . resize ( ( width , height ) , resample = Image . ANTIALIAS )
2009-01-05 14:30:08 +02:00
string = StringIO ( )
image . save ( string , format = ' PNG ' )
return string . getvalue ( )
2009-06-30 12:12:43 +03:00
2009-10-22 15:19:26 +03:00
class JSONField ( models . TextField ) :
2009-06-30 12:12:43 +03:00
"""
2009-10-22 15:19:26 +03:00
JSONField is a generic textfield that neatly serializes / unserializes
JSON objects seamlessly .
Django snippet #1478
2009-06-30 12:12:43 +03:00
"""
2009-10-22 15:19:26 +03:00
2009-06-30 12:12:43 +03:00
__metaclass__ = models . SubfieldBase
def to_python ( self , value ) :
2009-10-22 15:19:26 +03:00
if value == " " :
return None
try :
if isinstance ( value , basestring ) :
return json . loads ( value )
except ValueError :
pass
return value
2011-08-11 13:02:41 +03:00
def get_prep_value ( self , value ) :
2009-10-22 15:19:26 +03:00
if value == " " :
return None
if isinstance ( value , dict ) :
value = json . dumps ( value , cls = DjangoJSONEncoder )
2011-08-11 13:02:41 +03:00
return super ( JSONField , self ) . get_prep_value ( value )