Giter VIP home page Giter VIP logo

django-hstore-mixin's Introduction

Django Hstore Mixin

Mixin to allow usage of django-hstore whilst maintaining common Python data types.

Introduction

This is an add-on for the django-hstore library. While the django-hstore library does many amazing things, it suffers from the fact that does not maintain many datatypes (unless the newer schema mode is used, which is somewhat of a manual process). This is due to the fact that Postgresql can only store values as String objects.

To get around this limitation, the django-hstore-mixin creates a property on a model that acts as a proxy for the django-hstore field. Anything put into this field is serialized to JSON on input and deserialized from JSON on retrieval.

Note: Datetime objects will be serialized to ISO Format upon entrance into DB but will not be deserialized upon retrieval.

Installation

  1. Install django-hstore as per it's installation instructions.

  2. Install django-hstore-mixin:

    -e [email protected]:ospreyinformatics/django-hstore-mixin.git@[VERSION_TAG]#egg=django_hstore_mixin

  3. That's about it, no need to touch your INSTALLED_APPS. Just import and use the mixin as needed!

Usage

To use the django-hstore-mixin, simply import the HstoreMixin and use it in a model's base.

from django_hstore_mixin.models import HstoreMixin


class ExampleModel(HstoreMixin):
    """
    A model with a Django Hstore object that retains data types.
    """
    name = models.CharField(max_length=128, null=True, blank=True)

Now, the model with have a dictionary-like data property and a hidden _data field, which is the actual django-hstore field.
Anything written-to/read-from data will be serialized/deserialized to/from JSON and stored the _data field. Additionally, data written to the to data field will undergo some basic validation to ensure that it can be properly serialized to JSON.

instance = ExampleModel.objects.create(
    data=dict(
        int=1,
        string='foo',
        date=datetime.datetime.now(),
        list=[1, 'two'],
        dict=dict(a=1)
    )
)

>>> instance.data.get('int')    # Still an int...
1
>>> instance.data.get('string') # Naturally, still a string...
u'foo'
>>> instance.data.get('list')   # Still a list...
[1, u'two']
>>> instance.data.get('dict')   # Still a dict...
{u'a': 1}
>>> instance.data.get('date')   # Oops, not a datetime. An isoformat datetime string...
u'2014-10-14T19:54:39.248970'

>>> instance.data               # Returned as a dict-like object
{'date': u'2014-10-14T19:54:39.248970', 'int': 1, 'list': [1, u'two'], 'string': u'foo', 'dict': {u'a': 1}}
>>> type(instance.data)         # Not actually a dict
<class 'django_hstore_mixin.data_types.JsonDict'>
>>> isinstance(instance.data, dict)  # But an instance of a dict
True

During all of this, you can view how the data is serialized by looking at the _data property...

>>> instance._data.get('int')    # Stored as a JSON string of an int...
'1'
>>> instance._data.get('string') # Stored as a JSON string of a string...
'"foo"'
>>> instance._data.get('list')   # Stored as a JSON string of a list...
'[1, "two"]'
>>> instance._data.get('dict')   # Stored as a JSON string of a dict...
'{"a": 1}'
>>> instance._data.get('date')   # Stored as a JSON string of an isoformat datetime string...
'"2014-10-14T19:54:39.248970"'

>>> instance._data
{'date': '"2014-10-14T19:54:39.248970"', 'int': '1', 'list': '[1, "two"]', 'string': '"foo"', 'dict': '{"a": 1}'}
>>> type(instance._data)
<class 'django_hstore.dict.HStoreDict'>

Limitations

Currently, the data property name and _data field name is hardcoded. Additionally, the objects manager is overwritten with the hstore.HStoreManager().

If you would like to have multiple type-preserved hstore fields on the same model, want an hstore field with a name other than data, or need to avoid using the mixin for any other reason, you can add a field and a property interface in a manner like so:

from django.db import models
from django_hstore import hstore
from django_hstore_mixin.data_types import JsonDict
from django_hstore_mixin.serializers import serializeDict

class MyModel(models.Model):
    _myfield = hstore.DictionaryField('A dictionary field not named "data"')  # Hidden by prepending with an underscore

    @property
    def myfield(self):
        """ Decode myfield from JSON """
        return JsonDict(self._myfield, modelInstance=self, datafield='_myfield')
    @myfield.setter
    def myfield(self, value):
        """ Encode myfield to JSON """
        if not self._myfield:
          self._myfield = serializeDict(value)
        else:
          self._myfield = JsonDict(value, modelInstance=self, datafield='_myfield')

Running tests

Assuming one has the dependencies installed, and a PostgreSQL 9.0+ server up and running:

python runtests.py

By default the tests run with the postgis backend.

If you want to run the tests with psycopg2 backend you can do:

python runtests.py --settings=settings_psycopg

You might need to tweak the DB settings according to your DB configuration.

If you need to do so you can copy the file local_settings.py.example to local_settings.py and add your database tweaks on it. local_settings.py will be automatically imported in settings.py. The same applies for local_settings_psycopg.py.example, which will be imported in local_settings_psycopg.py.

If after running this command you get an error saying:

type "hstore" does not exist

Try this:

psql template1 -c 'create extension hstore;'

More details here on link: http://clarkdave.net/2012/09/postgresql-error-type-hstore-does-not-exist/[PostgreSQL error type hstore does not exist].

Contributions/Issues

The preferred way to make a contribution to the django-hstore-mixin is by forking the repo, making changes, and then opening a Pull Request.

The preferred way to raise attention to a bug/issue is by opening an Issue.

django-hstore-mixin's People

Contributors

alukach avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.