7

I would like to use Postgresql specific JSONField in Django, however, I have not found a way to test with sqlite environment.

Any tip for elegant way?

7
  • What do mean by testing JsonField? Commented Oct 13, 2016 at 7:06
  • 1
    If you use Postgres-specific functionality, then obviously you need to run your tests against Postgres as well. Commented Oct 13, 2016 at 14:33
  • 1
    @SardorbekImomaliev sqlite based test would not run if I define JsonField because sqlite does not support JsonField, but I want to still run integration test. Commented Oct 13, 2016 at 14:37
  • 2
    @DanielRoseman I would like to avoid to run test with postgresql on local, I prefer to use sqlite in order to speed up. That's why I posted here to hear some better solution other than run with postgresql. Perhaps dynamically changing JsonField to plaintext or something. Commented Oct 13, 2016 at 14:41
  • 1
    Well, I assume that he's not really up to testing the JsonField - but his models include the JsonField and that alone is a problem. So if you don't care about having the exact same environment for testing, your only option is to dynamically replace it with something that will be good enough for your testing. Commented May 9, 2018 at 21:08

1 Answer 1

2

If you are using Django3.1, The JSON1 extension can be used. If you are running a Django version less than 3.1, below code may help:

import json

from django.conf import settings
from django.contrib.postgres.fields import (
    JSONField as DjangoJSONField,
    ArrayField as DjangoArrayField,
)
from django.db.models import Field


class JSONField(DjangoJSONField):
    pass


class ArrayField(DjangoArrayField):
    pass


if 'sqlite' in settings.DATABASES['default']['ENGINE']:
    class JSONField(Field):
        def db_type(self, connection):
            return 'text'

        def from_db_value(self, value, expression, connection):
            if value is not None:
                return self.to_python(value)
            return value

        def to_python(self, value):
            if value is not None:
                try:
                    return json.loads(value)
                except (TypeError, ValueError):
                    return value
            return value

        def get_prep_value(self, value):
            if value is not None:
                return str(json.dumps(value))
            return value

        def value_to_string(self, obj):
            return self.value_from_object(obj)


    class ArrayField(JSONField):
        def __init__(self, base_field, size=None, **kwargs):
            """Care for DjanroArrayField's kwargs."""
            self.base_field = base_field
            self.size = size
            super().__init__(**kwargs)

        def deconstruct(self):
            """Need to create migrations properly."""
            name, path, args, kwargs = super().deconstruct()
            kwargs.update({
                'base_field': self.base_field.clone(),
                'size': self.size,
            })
            return name, path, args, kwargs

Import the JSONField from this file in your project and it will adjust itself for both SQLite and PostgreSQL.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.