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?

Jun
  • 351
  • 3
  • 13
  • What do mean by testing JsonField? – Sardorbek Imomaliev Oct 13 '16 at 07:06
  • 1
    If you use Postgres-specific functionality, then obviously you need to run your tests against Postgres as well. – Daniel Roseman Oct 13 '16 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. – Jun Oct 13 '16 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. – Jun Oct 13 '16 at 14:41
  • But then it wouldn't be a real test, so what's the point? – Daniel Roseman Oct 13 '16 at 15:00
  • 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. – smido May 09 '18 at 21:08
  • I want to run the unit tests as part of the docker build process. I don't want to install a Postgres as part of the docker build as it would make my build heavier just for the sake of unit testing. if this is the only option then okay, I will go ahead and install Postgres in the docker-machine and create DB, etc but it would really help if the process if we could use some way to use json fields in sqlite just for the sake of unit testing. – Utkarsh Sharma Apr 08 '21 at 03:38

1 Answers1

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.

Utkarsh Sharma
  • 323
  • 4
  • 14