django-jsonfield-0.9.12/0000755000076500000240000000000012251451242015106 5ustar mattstaff00000000000000django-jsonfield-0.9.12/django_jsonfield.egg-info/0000755000076500000240000000000012251451242022077 5ustar mattstaff00000000000000django-jsonfield-0.9.12/django_jsonfield.egg-info/dependency_links.txt0000644000076500000240000000000112251451240026143 0ustar mattstaff00000000000000 django-jsonfield-0.9.12/django_jsonfield.egg-info/PKG-INFO0000644000076500000240000001254412251451240023200 0ustar mattstaff00000000000000Metadata-Version: 1.1 Name: django-jsonfield Version: 0.9.12 Summary: JSONField for django models Home-page: http://bitbucket.org/schinckel/django-jsonfield/ Author: Matthew Schinckel Author-email: matt@schinckel.net License: UNKNOWN Description: django-jsonfield =================== .. image:: https://drone.io/bitbucket.org/schinckel/django-jsonfield/status.png .. image:: https://drone.io/bitbucket.org/schinckel/django-jsonfield/files/.coverage/coverage_status.png I had a serious need for a JSON field for django. There were a couple out there, but none packaged up nicely on bitbucket/github that were usable with ``pip install -e``. So I took the code from `David Cramer's blog`_, and packaged it up. Usage ----- To use, just install the package, and then use the field:: from django.db import models import jsonfield class MyModel(models.Model): the_json = jsonfield.JSONField() Now, it will validate the JSON on entry, and store it as a string in the database. When you instantiate/fetch the object, it will be turned back into a python list/dict/string. There is also a ``TypedJSONField``, that allows you to define data types that must be included within each object in the array. More documentation to follow. Notes ~~~~~ If no ``default`` is provided, and ``null=True`` is not passed in to the field constructor, then a default of ``{}`` will be used. There are also a couple of other bits and bobs: Extras ------ jsonify templatetag ~~~~~~~~~~~~~~~~~~~ This allows you to convert a python data structure into JSON within a template:: {% load jsonify %} History ---------- 0.9.12 ~~~~~~ Cache the result of db_type. Handle incoming data from multiple select widget better. 0.9.9 ~~~~~ Finally strip out non-required files. 0.9.8 ~~~~~ Remove freezegun workarounds. Fix broken build. 0.9.4 ~~~~~ Fixes for mutable defaults: we serialize and then deserialize in this case, so you can still use ``default={}``. 0.9.3 ~~~~~ Remove support for storing data using Postgres' 9.2's JSON data type, as you cannot currently query against this! Remove support for django < 1.3. 0.9.0 ~~~~~ Add LICENSE file. Added TypedJSONField. 0.8.10 ~~~~~~ Allow ``{{ variable|jsonify }}`` to work with querysets. 0.8.8 ~~~~~ Prevent circular import problem with django 1.3.1 and gargoyle. 0.8.7 ~~~~~ Better handle null=True and blank=True: it should make sense what they do now. 0.8.5 ~~~~~ Allow for '{}' and '[]', and make them not appear to be None. 0.8.4 ~~~~~ Ensure the version number file is installed with the package. 0.8.3 ~~~~~ Store the version number in one place only, now. 0.8.2 ~~~~~ Oops. Packaging error prevented install from pypi. Added README.rst to manifest. 0.8.1 ~~~~~ Converting to string does nothing, as serializing a model instance with a JSONField would have a string version of that field, instead of it embedded inline. (Back to pre 0.8 behaviour). Added better querying support: (``field__contains={'key':'value','key2':'value2'}`` works.) Removed JSONTableWidget from package. 0.8 ~~~ (Many thanks to `IanLewis`_ for these features) Supports django 1.2 Supports callable and json serializable objects as default Implemented get_db_prep_value() Add tests and test runner. Removed JSONTableWidget from README. 0.7.1 ~~~~~ Don't fail when trying to install before django is installed. 0.7 ~~~ First time I tagged releases. Todo ---------- Allow for passing in a function to use for processing unknown data types. Convert date/time objects nicely to/from ISO strings (YYYY-mm-dd HH:MM:SS TZNAME). This is actually a bit tricky, as we don't know if we are expecting a date/time object. We may parse objects as we go, but there could be some performance issues with this. I'm tempted to say "only do this on TypedJSONField()" .. _David Cramer's blog: http://justcramer.com/2009/04/14/cleaning-up-with-json-and-sql/ .. _IanLewis: https://bitbucket.org/IanLewis Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Framework :: Django django-jsonfield-0.9.12/django_jsonfield.egg-info/SOURCES.txt0000644000076500000240000000120112251451242023755 0ustar mattstaff00000000000000LICENSE MANIFEST.in README.rst setup.py tests.py django_jsonfield.egg-info/PKG-INFO django_jsonfield.egg-info/SOURCES.txt django_jsonfield.egg-info/dependency_links.txt django_jsonfield.egg-info/top_level.txt jsonfield/VERSION jsonfield/__init__.py jsonfield/fields.py jsonfield/forms.py jsonfield/models.py jsonfield/utils.py jsonfield/widgets.py jsonfield/templatetags/__init__.py jsonfield/templatetags/jsonify.py jsonfield/tests/__init__.py jsonfield/tests/test_fields.py jsonfield/tests/test_forms.py jsonfield/tests/jsonfield_test_app/__init__.py jsonfield/tests/jsonfield_test_app/forms.py jsonfield/tests/jsonfield_test_app/models.pydjango-jsonfield-0.9.12/django_jsonfield.egg-info/top_level.txt0000644000076500000240000000001212251451240024620 0ustar mattstaff00000000000000jsonfield django-jsonfield-0.9.12/jsonfield/0000755000076500000240000000000012251451242017063 5ustar mattstaff00000000000000django-jsonfield-0.9.12/jsonfield/__init__.py0000644000076500000240000000024312240042352021167 0ustar mattstaff00000000000000import os __version__ = open(os.path.join(os.path.dirname(__file__),'VERSION')).read().strip() try: from .fields import JSONField except ImportError: passdjango-jsonfield-0.9.12/jsonfield/fields.py0000644000076500000240000001417412244570031020712 0ustar mattstaff00000000000000from __future__ import unicode_literals import json from django.core.exceptions import ValidationError from django.conf import settings from django.db import models, DatabaseError, transaction from django.utils.translation import ugettext_lazy as _ from django.utils import six from django.core.cache import cache from decimal import Decimal import datetime from .utils import default from .widgets import JSONWidget from .forms import JSONFormField from jsonfield import __version__ DB_TYPE_CACHE_KEY = ( 'django-jsonfield:db-type:%s' % __version__ + '%(ENGINE)s:%(HOST)s:%(PORT)s:%(NAME)s' ) class JSONField(six.with_metaclass(models.SubfieldBase, models.Field)): """ A field that will ensure the data entered into it is valid JSON. """ default_error_messages = { 'invalid': _("'%s' is not a valid JSON string.") } description = "JSON object" def __init__(self, *args, **kwargs): if not kwargs.get('null', False): kwargs['default'] = kwargs.get('default', dict) self.encoder_kwargs = { 'indent': kwargs.get('indent', getattr(settings, 'JSONFIELD_INDENT', None)) } super(JSONField, self).__init__(*args, **kwargs) self.validate(self.get_default(), None) def formfield(self, **kwargs): defaults = { 'form_class': JSONFormField, 'widget': JSONWidget } defaults.update(**kwargs) return super(JSONField, self).formfield(**defaults) def validate(self, value, model_instance): if not self.null and value is None: raise ValidationError(self.error_messages['null']) try: self.get_prep_value(value) except: raise ValidationError(self.error_messages['invalid'] % value) def get_default(self): if self.has_default(): default = self.default if callable(default): default = default() if isinstance(default, six.string_types): return json.loads(default) return json.loads(json.dumps(default)) return super(JSONField, self).get_default() def get_internal_type(self): return 'TextField' def db_type(self, connection): cache_key = DB_TYPE_CACHE_KEY % connection.settings_dict db_type = cache.get(cache_key) if not db_type: # Test to see if we support JSON querying. cursor = connection.cursor() try: sid = transaction.savepoint(using=connection.alias) cursor.execute('SELECT \'{}\'::json = \'{}\'::json;') except DatabaseError: transaction.savepoint_rollback(sid, using=connection.alias) db_type = 'text' else: db_type = 'json' cache.set(cache_key, db_type) return db_type def to_python(self, value): if isinstance(value, six.string_types): if value == "": if self.null: return None if self.blank: return "" try: value = json.loads(value) except ValueError: msg = self.error_messages['invalid'] % value raise ValidationError(msg) # TODO: Look for date/time/datetime objects within the structure? return value def get_db_prep_value(self, value, connection=None, prepared=None): return self.get_prep_value(value) def get_prep_value(self, value): if value is None: if not self.null and self.blank: return "" return None return json.dumps(value, default=default, **self.encoder_kwargs) def get_prep_lookup(self, lookup_type, value): if lookup_type in ["exact", "iexact"]: return self.to_python(self.get_prep_value(value)) if lookup_type == "in": return [self.to_python(self.get_prep_value(v)) for v in value] if lookup_type == "isnull": return value if lookup_type in ["contains", "icontains"]: if isinstance(value, (list, tuple)): raise TypeError("Lookup type %r not supported with argument of %s" % ( lookup_type, type(value).__name__ )) # Need a way co combine the values with '%', but don't escape that. return self.get_prep_value(value)[1:-1].replace(', ', r'%') if isinstance(value, dict): return self.get_prep_value(value)[1:-1] return self.to_python(self.get_prep_value(value)) raise TypeError('Lookup type %r not supported' % lookup_type) def value_to_string(self, obj): return self._get_val_from_obj(obj) class TypedJSONField(JSONField): """ """ def __init__(self, *args, **kwargs): self.json_required_fields = kwargs.pop('required_fields', {}) self.json_validators = kwargs.pop('validators', []) super(TypedJSONField, self).__init__(*args, **kwargs) def cast_required_fields(self, obj): if not obj: return for field_name, field_type in self.json_required_fields.items(): obj[field_name] = field_type.to_python(obj[field_name]) def to_python(self, value): value = super(TypedJSONField, self).to_python(value) if isinstance(value, list): for item in value: self.cast_required_fields(item) else: self.cast_required_fields(value) return value def validate(self, value, model_instance): super(TypedJSONField, self).validate(value, model_instance) for v in self.json_validators: if isinstance(value, list): for item in value: v(item) else: v(value) try: from south.modelsinspector import add_introspection_rules add_introspection_rules([], ['^jsonfield\.fields\.JSONField']) add_introspection_rules([], ['^jsonfield\.fields\.TypedJSONField']) except ImportError: passdjango-jsonfield-0.9.12/jsonfield/forms.py0000644000076500000240000000165312251450172020571 0ustar mattstaff00000000000000import json from django import forms from django.utils import six from .widgets import JSONWidget class JSONFormField(forms.CharField): empty_values = [None, ''] def __init__(self, *args, **kwargs): if 'widget' not in kwargs: kwargs['widget'] = JSONWidget super(JSONFormField, self).__init__(*args, **kwargs) def to_python(self, value): if isinstance(value, six.string_types) and value: try: return json.loads(value) except Exception as exc: raise forms.ValidationError( 'JSON decode error: %s' % (unicode(exc),) ) else: return value def validate(self, value): # This is required in older django versions. if value in self.empty_values and self.required: raise forms.ValidationError(self.error_messages['required'], code='required')django-jsonfield-0.9.12/jsonfield/models.py0000644000076500000240000000000012240042352020702 0ustar mattstaff00000000000000django-jsonfield-0.9.12/jsonfield/templatetags/0000755000076500000240000000000012251451242021555 5ustar mattstaff00000000000000django-jsonfield-0.9.12/jsonfield/templatetags/__init__.py0000644000076500000240000000000012240042352023650 0ustar mattstaff00000000000000django-jsonfield-0.9.12/jsonfield/templatetags/jsonify.py0000644000076500000240000000060612251451123023610 0ustar mattstaff00000000000000import json from django import template from django.utils.safestring import mark_safe from jsonfield.utils import TZAwareJSONEncoder register = template.Library() @register.filter def jsonify(value): # If we have a queryset, then convert it into a list. if getattr(value, 'all', False): value = list(value) return mark_safe(json.dumps(value, cls=TZAwareJSONEncoder)) django-jsonfield-0.9.12/jsonfield/tests/0000755000076500000240000000000012251451242020225 5ustar mattstaff00000000000000django-jsonfield-0.9.12/jsonfield/tests/__init__.py0000644000076500000240000000006412240042352022332 0ustar mattstaff00000000000000from .test_fields import * from .test_forms import *django-jsonfield-0.9.12/jsonfield/tests/jsonfield_test_app/0000755000076500000240000000000012251451242024101 5ustar mattstaff00000000000000django-jsonfield-0.9.12/jsonfield/tests/jsonfield_test_app/__init__.py0000644000076500000240000000000012240042352026174 0ustar mattstaff00000000000000django-jsonfield-0.9.12/jsonfield/tests/jsonfield_test_app/forms.py0000644000076500000240000000050112240042352025571 0ustar mattstaff00000000000000from django import forms from jsonfield.forms import JSONFormField from .models import JSONFieldTestModel class JSONTestForm(forms.Form): json_data = JSONFormField() optional_json_data = JSONFormField(required=False) class JSONTestModelForm(forms.ModelForm): class Meta: model = JSONFieldTestModel django-jsonfield-0.9.12/jsonfield/tests/jsonfield_test_app/models.py0000644000076500000240000000124212240042352025731 0ustar mattstaff00000000000000from django.db import models from jsonfield.fields import JSONField class JSONFieldTestModel(models.Model): json = JSONField("test", null=True, blank=True) class Meta: app_label = 'jsonfield' class JSONFieldWithDefaultTestModel(models.Model): json = JSONField(default={"sukasuka": "YAAAAAZ"}) class Meta: app_label = 'jsonfield' class BlankJSONFieldTestModel(models.Model): null_json = JSONField(null=True) blank_json = JSONField(blank=True) class Meta: app_label = 'jsonfield' class CallableDefaultModel(models.Model): json = JSONField(default=lambda:{'x':2}) class Meta: app_label = 'jsonfield'django-jsonfield-0.9.12/jsonfield/tests/test_fields.py0000644000076500000240000001462112251450324023110 0ustar mattstaff00000000000000#:coding=utf-8: from django.test import TestCase as DjangoTestCase from django.utils import unittest from django.utils.encoding import force_text from django import forms from jsonfield.tests.jsonfield_test_app.models import * from jsonfield.fields import JSONField class JSONFieldTest(DjangoTestCase): def test_json_field(self): obj = JSONFieldTestModel(json='''{ "spam": "eggs" }''') self.assertEquals(obj.json, {'spam':'eggs'}) def test_json_field_empty(self): obj = JSONFieldTestModel(json='') self.assertEquals(obj.json, None) def test_json_field_save(self): JSONFieldTestModel.objects.create( id=10, json='''{ "spam": "eggs" }''', ) obj2 = JSONFieldTestModel.objects.get(id=10) self.assertEquals(obj2.json, {'spam':'eggs'}) def test_json_field_save_empty(self): JSONFieldTestModel.objects.create(id=10, json='') obj2 = JSONFieldTestModel.objects.get(id=10) self.assertEquals(obj2.json, None) def test_db_prep_save(self): field = JSONField("test") field.set_attributes_from_name("json") self.assertEquals(None, field.get_db_prep_save(None, connection=None)) self.assertEquals('{"spam": "eggs"}', field.get_db_prep_save({"spam": "eggs"}, connection=None)) def test_formfield(self): from jsonfield.forms import JSONFormField from jsonfield.widgets import JSONWidget field = JSONField("test") field.set_attributes_from_name("json") formfield = field.formfield() self.assertEquals(type(formfield), JSONFormField) self.assertEquals(type(formfield.widget), JSONWidget) def test_formfield_clean_blank(self): field = JSONField("test") formfield = field.formfield() self.assertRaisesMessage(forms.ValidationError, force_text(formfield.error_messages['required']), formfield.clean, value='') def test_formfield_clean_none(self): field = JSONField("test") formfield = field.formfield() self.assertRaisesMessage(forms.ValidationError, force_text(formfield.error_messages['required']), formfield.clean, value=None) def test_formfield_null_and_blank_clean_blank(self): field = JSONField("test", null=True, blank=True) formfield = field.formfield() self.assertEquals(formfield.clean(value=''), '') def test_formfield_null_and_blank_clean_none(self): field = JSONField("test", null=True, blank=True) formfield = field.formfield() self.assertEquals(formfield.clean(value=None), None) def test_formfield_blank_clean_blank(self): field = JSONField("test", null=False, blank=True) formfield = field.formfield() self.assertEquals(formfield.clean(value=''), '') def test_formfield_blank_clean_none(self): # Hmm, I'm not sure how to do this. What happens if we pass a # None to a field that has null=False? field = JSONField("test", null=False, blank=True) formfield = field.formfield() self.assertEquals(formfield.clean(value=None), None) def test_default_value(self): obj = JSONFieldWithDefaultTestModel.objects.create() obj = JSONFieldWithDefaultTestModel.objects.get(id=obj.id) self.assertEquals(obj.json, {'sukasuka': 'YAAAAAZ'}) def test_query_object(self): JSONFieldTestModel.objects.create(json={}) JSONFieldTestModel.objects.create(json={'foo':'bar'}) self.assertEquals(2, JSONFieldTestModel.objects.all().count()) self.assertEquals(1, JSONFieldTestModel.objects.exclude(json={}).count()) self.assertEquals(1, JSONFieldTestModel.objects.filter(json={}).count()) self.assertEquals(1, JSONFieldTestModel.objects.filter(json={'foo':'bar'}).count()) self.assertEquals(1, JSONFieldTestModel.objects.filter(json__contains={'foo':'bar'}).count()) JSONFieldTestModel.objects.create(json={'foo':'bar', 'baz':'bing'}) self.assertEquals(2, JSONFieldTestModel.objects.filter(json__contains={'foo':'bar'}).count()) self.assertEquals(1, JSONFieldTestModel.objects.filter(json__contains={'baz':'bing', 'foo':'bar'}).count()) self.assertEquals(2, JSONFieldTestModel.objects.filter(json__contains='foo').count()) # This code needs to be implemented! self.assertRaises(TypeError, lambda:JSONFieldTestModel.objects.filter(json__contains=['baz', 'foo'])) def test_query_isnull(self): JSONFieldTestModel.objects.create(json=None) JSONFieldTestModel.objects.create(json={}) JSONFieldTestModel.objects.create(json={'foo':'bar'}) self.assertEquals(1, JSONFieldTestModel.objects.filter(json=None).count()) self.assertEquals(None, JSONFieldTestModel.objects.get(json=None).json) def test_jsonfield_blank(self): BlankJSONFieldTestModel.objects.create(blank_json='', null_json=None) obj = BlankJSONFieldTestModel.objects.get() self.assertEquals(None, obj.null_json) self.assertEquals("", obj.blank_json) obj.save() obj = BlankJSONFieldTestModel.objects.get() self.assertEquals(None, obj.null_json) self.assertEquals("", obj.blank_json) def test_callable_default(self): CallableDefaultModel.objects.create() obj = CallableDefaultModel.objects.get() self.assertEquals({'x':2}, obj.json) def test_callable_default_overridden(self): CallableDefaultModel.objects.create(json={'x':3}) obj = CallableDefaultModel.objects.get() self.assertEquals({'x':3}, obj.json) def test_mutable_default_checking(self): obj1 = JSONFieldWithDefaultTestModel() obj2 = JSONFieldWithDefaultTestModel() obj1.json['foo'] = 'bar' self.assertNotIn('foo', obj2.json) def test_invalid_json(self): obj = JSONFieldTestModel() obj.json = '{"foo": 2}' self.assertIn('foo', obj.json) with self.assertRaises(forms.ValidationError): obj.json = '{"foo"}' def test_invalid_json_default(self): with self.assertRaises(ValueError): field = JSONField('test', default='{"foo"}') class SavingModelsTest(DjangoTestCase): def test_saving_null(self): obj = BlankJSONFieldTestModel.objects.create(blank_json='', null_json=None) self.assertEquals('', obj.blank_json) self.assertEquals(None, obj.null_json)django-jsonfield-0.9.12/jsonfield/tests/test_forms.py0000644000076500000240000000352112251451030022760 0ustar mattstaff00000000000000from django.test import TestCase as DjangoTestCase from django.utils import unittest from django.forms import ValidationError from jsonfield.forms import JSONFormField from jsonfield.tests.jsonfield_test_app.forms import JSONTestForm, JSONTestModelForm class JSONFormFieldTest(DjangoTestCase): def test_form_field_clean_empty_object(self): field = JSONFormField(required=False) self.assertEquals({}, field.clean('{}')) def test_form_field_clean_object(self): field = JSONFormField(required=False) self.assertEquals( {'foo':'bar', 'baz':2}, field.clean('{"foo":"bar","baz":2}') ) def test_form_field_clean_empty_array(self): field = JSONFormField(required=False) self.assertEquals([],field.clean('[]')) def test_required_form_field_array(self): field = JSONFormField(required=True) self.assertEquals([], field.clean('[]')) def test_required_form_field_object(self): field = JSONFormField(required=True) self.assertEquals({}, field.clean('{}')) def test_required_form_field_empty(self): field = JSONFormField(required=True) with self.assertRaises(ValidationError): field.clean('') def test_invalid_json(self): field = JSONFormField(required=True) with self.assertRaises(ValidationError): field.clean('{"foo"}') class JSONFormTest(DjangoTestCase): def test_form_clean(self): form = JSONTestForm({}) self.assertFalse(form.is_valid()) class JSONFormMultipleSelectFieldTest(DjangoTestCase): def test_multiple_select_data(self): form = JSONTestForm({'json_data': [u'SA', u'WA']}) assert form.is_valid() self.assertEquals([u'SA', u'WA'], form.cleaned_data['json_data']) django-jsonfield-0.9.12/jsonfield/utils.py0000644000076500000240000000161412240042352020573 0ustar mattstaff00000000000000import datetime from decimal import Decimal from django.core.serializers.json import DjangoJSONEncoder class TZAwareJSONEncoder(DjangoJSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): return obj.strftime("%Y-%m-%d %H:%M:%S%z") return super(TZAwareJSONEncoder, self).default(obj) def default(o): if hasattr(o, 'to_json'): return o.to_json() if isinstance(o, Decimal): return str(o) if isinstance(o, datetime.datetime): if o.tzinfo: return o.strftime('%Y-%m-%dT%H:%M:%S%z') return o.strftime("%Y-%m-%dT%H:%M:%S") if isinstance(o, datetime.date): return o.strftime("%Y-%m-%d") if isinstance(o, datetime.time): if o.tzinfo: return o.strftime('%H:%M:%S%z') return o.strftime("%H:%M:%S") raise TypeError(repr(o) + " is not JSON serializable") django-jsonfield-0.9.12/jsonfield/VERSION0000644000076500000240000000000712251451225020131 0ustar mattstaff000000000000000.9.12 django-jsonfield-0.9.12/jsonfield/widgets.py0000644000076500000240000000072112245772065021117 0ustar mattstaff00000000000000import json from django import forms from django.conf import settings from .utils import default class JSONWidget(forms.Textarea): def render(self, name, value, attrs=None): if value is None: value = "" if not isinstance(value, basestring): value = json.dumps(value, indent=2, default=default) return super(JSONWidget, self).render(name, value, attrs) class JSONSelectWidget(forms.SelectMultiple): pass django-jsonfield-0.9.12/LICENSE0000644000076500000240000000265712240042352016121 0ustar mattstaff00000000000000Copyright (c) 2012, Matthew Schinckel. 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. * The names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 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 MATTHEW SCHINCKEL 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. django-jsonfield-0.9.12/MANIFEST.in0000644000076500000240000000022012240042352016632 0ustar mattstaff00000000000000recursive-include jsonfield *.py include jsonfield/VERSION include README.rst include tests.py include LICENSE recursive-exclude jsonfield *.pycdjango-jsonfield-0.9.12/PKG-INFO0000644000076500000240000001254412251451242016211 0ustar mattstaff00000000000000Metadata-Version: 1.1 Name: django-jsonfield Version: 0.9.12 Summary: JSONField for django models Home-page: http://bitbucket.org/schinckel/django-jsonfield/ Author: Matthew Schinckel Author-email: matt@schinckel.net License: UNKNOWN Description: django-jsonfield =================== .. image:: https://drone.io/bitbucket.org/schinckel/django-jsonfield/status.png .. image:: https://drone.io/bitbucket.org/schinckel/django-jsonfield/files/.coverage/coverage_status.png I had a serious need for a JSON field for django. There were a couple out there, but none packaged up nicely on bitbucket/github that were usable with ``pip install -e``. So I took the code from `David Cramer's blog`_, and packaged it up. Usage ----- To use, just install the package, and then use the field:: from django.db import models import jsonfield class MyModel(models.Model): the_json = jsonfield.JSONField() Now, it will validate the JSON on entry, and store it as a string in the database. When you instantiate/fetch the object, it will be turned back into a python list/dict/string. There is also a ``TypedJSONField``, that allows you to define data types that must be included within each object in the array. More documentation to follow. Notes ~~~~~ If no ``default`` is provided, and ``null=True`` is not passed in to the field constructor, then a default of ``{}`` will be used. There are also a couple of other bits and bobs: Extras ------ jsonify templatetag ~~~~~~~~~~~~~~~~~~~ This allows you to convert a python data structure into JSON within a template:: {% load jsonify %} History ---------- 0.9.12 ~~~~~~ Cache the result of db_type. Handle incoming data from multiple select widget better. 0.9.9 ~~~~~ Finally strip out non-required files. 0.9.8 ~~~~~ Remove freezegun workarounds. Fix broken build. 0.9.4 ~~~~~ Fixes for mutable defaults: we serialize and then deserialize in this case, so you can still use ``default={}``. 0.9.3 ~~~~~ Remove support for storing data using Postgres' 9.2's JSON data type, as you cannot currently query against this! Remove support for django < 1.3. 0.9.0 ~~~~~ Add LICENSE file. Added TypedJSONField. 0.8.10 ~~~~~~ Allow ``{{ variable|jsonify }}`` to work with querysets. 0.8.8 ~~~~~ Prevent circular import problem with django 1.3.1 and gargoyle. 0.8.7 ~~~~~ Better handle null=True and blank=True: it should make sense what they do now. 0.8.5 ~~~~~ Allow for '{}' and '[]', and make them not appear to be None. 0.8.4 ~~~~~ Ensure the version number file is installed with the package. 0.8.3 ~~~~~ Store the version number in one place only, now. 0.8.2 ~~~~~ Oops. Packaging error prevented install from pypi. Added README.rst to manifest. 0.8.1 ~~~~~ Converting to string does nothing, as serializing a model instance with a JSONField would have a string version of that field, instead of it embedded inline. (Back to pre 0.8 behaviour). Added better querying support: (``field__contains={'key':'value','key2':'value2'}`` works.) Removed JSONTableWidget from package. 0.8 ~~~ (Many thanks to `IanLewis`_ for these features) Supports django 1.2 Supports callable and json serializable objects as default Implemented get_db_prep_value() Add tests and test runner. Removed JSONTableWidget from README. 0.7.1 ~~~~~ Don't fail when trying to install before django is installed. 0.7 ~~~ First time I tagged releases. Todo ---------- Allow for passing in a function to use for processing unknown data types. Convert date/time objects nicely to/from ISO strings (YYYY-mm-dd HH:MM:SS TZNAME). This is actually a bit tricky, as we don't know if we are expecting a date/time object. We may parse objects as we go, but there could be some performance issues with this. I'm tempted to say "only do this on TypedJSONField()" .. _David Cramer's blog: http://justcramer.com/2009/04/14/cleaning-up-with-json-and-sql/ .. _IanLewis: https://bitbucket.org/IanLewis Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Framework :: Django django-jsonfield-0.9.12/README.rst0000644000076500000240000000730512251451217016604 0ustar mattstaff00000000000000django-jsonfield =================== .. image:: https://drone.io/bitbucket.org/schinckel/django-jsonfield/status.png .. image:: https://drone.io/bitbucket.org/schinckel/django-jsonfield/files/.coverage/coverage_status.png I had a serious need for a JSON field for django. There were a couple out there, but none packaged up nicely on bitbucket/github that were usable with ``pip install -e``. So I took the code from `David Cramer's blog`_, and packaged it up. Usage ----- To use, just install the package, and then use the field:: from django.db import models import jsonfield class MyModel(models.Model): the_json = jsonfield.JSONField() Now, it will validate the JSON on entry, and store it as a string in the database. When you instantiate/fetch the object, it will be turned back into a python list/dict/string. There is also a ``TypedJSONField``, that allows you to define data types that must be included within each object in the array. More documentation to follow. Notes ~~~~~ If no ``default`` is provided, and ``null=True`` is not passed in to the field constructor, then a default of ``{}`` will be used. There are also a couple of other bits and bobs: Extras ------ jsonify templatetag ~~~~~~~~~~~~~~~~~~~ This allows you to convert a python data structure into JSON within a template:: {% load jsonify %} History ---------- 0.9.12 ~~~~~~ Cache the result of db_type. Handle incoming data from multiple select widget better. 0.9.9 ~~~~~ Finally strip out non-required files. 0.9.8 ~~~~~ Remove freezegun workarounds. Fix broken build. 0.9.4 ~~~~~ Fixes for mutable defaults: we serialize and then deserialize in this case, so you can still use ``default={}``. 0.9.3 ~~~~~ Remove support for storing data using Postgres' 9.2's JSON data type, as you cannot currently query against this! Remove support for django < 1.3. 0.9.0 ~~~~~ Add LICENSE file. Added TypedJSONField. 0.8.10 ~~~~~~ Allow ``{{ variable|jsonify }}`` to work with querysets. 0.8.8 ~~~~~ Prevent circular import problem with django 1.3.1 and gargoyle. 0.8.7 ~~~~~ Better handle null=True and blank=True: it should make sense what they do now. 0.8.5 ~~~~~ Allow for '{}' and '[]', and make them not appear to be None. 0.8.4 ~~~~~ Ensure the version number file is installed with the package. 0.8.3 ~~~~~ Store the version number in one place only, now. 0.8.2 ~~~~~ Oops. Packaging error prevented install from pypi. Added README.rst to manifest. 0.8.1 ~~~~~ Converting to string does nothing, as serializing a model instance with a JSONField would have a string version of that field, instead of it embedded inline. (Back to pre 0.8 behaviour). Added better querying support: (``field__contains={'key':'value','key2':'value2'}`` works.) Removed JSONTableWidget from package. 0.8 ~~~ (Many thanks to `IanLewis`_ for these features) Supports django 1.2 Supports callable and json serializable objects as default Implemented get_db_prep_value() Add tests and test runner. Removed JSONTableWidget from README. 0.7.1 ~~~~~ Don't fail when trying to install before django is installed. 0.7 ~~~ First time I tagged releases. Todo ---------- Allow for passing in a function to use for processing unknown data types. Convert date/time objects nicely to/from ISO strings (YYYY-mm-dd HH:MM:SS TZNAME). This is actually a bit tricky, as we don't know if we are expecting a date/time object. We may parse objects as we go, but there could be some performance issues with this. I'm tempted to say "only do this on TypedJSONField()" .. _David Cramer's blog: http://justcramer.com/2009/04/14/cleaning-up-with-json-and-sql/ .. _IanLewis: https://bitbucket.org/IanLewis django-jsonfield-0.9.12/setup.cfg0000644000076500000240000000007312251451242016727 0ustar mattstaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 django-jsonfield-0.9.12/setup.py0000644000076500000240000000131512240042352016614 0ustar mattstaff00000000000000import os from setuptools import setup setup( name = "django-jsonfield", version = open(os.path.join(os.path.dirname(__file__), 'jsonfield', 'VERSION')).read().strip(), description = "JSONField for django models", long_description = open("README.rst").read(), url = "http://bitbucket.org/schinckel/django-jsonfield/", author = "Matthew Schinckel", author_email = "matt@schinckel.net", packages = [ "jsonfield", ], classifiers = [ 'Programming Language :: Python', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Framework :: Django', ], test_suite='tests.main', include_package_data=True, ) django-jsonfield-0.9.12/tests.py0000644000076500000240000000330612240042352016620 0ustar mattstaff00000000000000import os import sys import unittest import doctest import django BASE_PATH = os.path.dirname(__file__) def main(db_engine='sqlite3'): """ Standalone django model test with a 'memory-only-django-installation'. You can play with a django model without a complete django app installation. http://www.djangosnippets.org/snippets/1044/ """ os.environ["DJANGO_SETTINGS_MODULE"] = "django.conf.global_settings" from django.conf import global_settings global_settings.INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'jsonfield', ) global_settings.DATABASES = { 'default': { 'ENGINE': 'django.db.backends.%s' % db_engine, 'NAME': 'django-jsonfield', } } global_settings.STATIC_URL = "/static/" global_settings.MEDIA_ROOT = os.path.join(BASE_PATH, 'static') global_settings.STATIC_ROOT = global_settings.MEDIA_ROOT global_settings.SECRET_KEY = '334ebe58-a77d-4321-9d01-a7d2cb8d3eea' global_settings.COVERAGE_REPORT_HTML_OUTPUT_DIR = os.path.join(BASE_PATH, '.coverage') global_settings.COVERAGE_USE_STDOUT = True global_settings.COVERAGE_PATH_EXCLUDES = ['.hg', 'templates', 'tests', 'sql', '__pycache__'] if os.environ.get('COVERAGE', None): from django_coverage import coverage_runner test_runner = coverage_runner.CoverageRunner else: from django.test.utils import get_runner test_runner = get_runner(global_settings) test_runner = test_runner() failures = test_runner.run_tests(['jsonfield']) sys.exit(failures) def test_postgres(): main('postgresql_psycopg2') if __name__ == '__main__': main()