from django.db import models from django.db.models import OneToOneField from django.utils import simplejson as json from django.core.serializers.json import DjangoJSONEncoder from django.db.models.fields.related import SingleRelatedObjectDescriptor 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}) obj.save() return obj class AutoOneToOneField(OneToOneField): ''' OneToOneField creates related object on first call if it doesnt exist yet. Use it instead of original OneToOne field. example: class MyProfile(models.Model): user = AutoOneToOneField(User, primary_key=True) home_page = models.URLField(max_length=255, blank=True) icq = models.IntegerField(max_length=255, null=True) ''' def contribute_to_related_class(self, cls, related): setattr(cls, related.get_accessor_name(), AutoSingleRelatedObjectDescriptor(related)) class JSONField(models.TextField): """ JSONField is a generic textfield that neatly serializes/unserializes JSON objects seamlessly. Django snippet #1478 example: class Page(models.Model): data = JSONField(blank=True, null=True) page = Page.objects.get(pk=5) page.data = {'title': 'test', 'type': 3} page.save() """ __metaclass__ = models.SubfieldBase def to_python(self, value): if value == "": return None try: if isinstance(value, basestring): return json.loads(value) except ValueError: pass return value def get_db_prep_save(self, value, *args, **kwargs): if value == "": return None if isinstance(value, dict): value = json.dumps(value, cls=DjangoJSONEncoder) return super(JSONField, self).get_db_prep_save(value, *args, **kwargs)