diff --git a/django_redshift_backend/base.py b/django_redshift_backend/base.py index 2f02b39..f4f58b0 100644 --- a/django_redshift_backend/base.py +++ b/django_redshift_backend/base.py @@ -10,6 +10,7 @@ import re import uuid import logging +import json import django from django.utils import timezone @@ -53,6 +54,7 @@ class DatabaseFeatures(BasePGDatabaseFeatures): supports_column_check_constraints = False can_distinct_on_fields = False allows_group_by_selected_pks = False + has_native_json_field = False # Redshift doesn't support JSONField. has_native_uuid_field = False supports_aggregate_filter_clause = False supports_combined_alters = False # since django-1.8 @@ -166,6 +168,10 @@ def prepare_join_on_clause(self, lhs_table, lhs_field, rhs_table, rhs_field): return lhs_expr, rhs_expr + # copy from djang 4.2 base/operations.py + def adapt_json_value(self, value, encoder): + return json.dumps(value, cls=encoder) + def _get_type_default(field): internal_type = field.get_internal_type() @@ -1124,6 +1130,9 @@ def remove_field(self, model, field): redshift_data_types = { "AutoField": "integer identity(1, 1)", "BigAutoField": "bigint identity(1, 1)", + # Redshift doesn't support JSONField. + # https://docs.aws.amazon.com/redshift/latest/dg/federated-data-types.html + "JSONField": "varchar", "TextField": "varchar(max)", # text must be varchar(max) "UUIDField": "varchar(36)", # redshift doesn't support uuid fields "BinaryField": "varbyte(%(max_length)s)", diff --git a/tests/test_migrations.py b/tests/test_migrations.py index c454f9c..51f1892 100644 --- a/tests/test_migrations.py +++ b/tests/test_migrations.py @@ -583,3 +583,30 @@ def test_foreign_key_to_non_id(self): '''ALTER TABLE "test_pony" ADD CONSTRAINT "test_pony_remote_e347b432_uniq" UNIQUE ("remote");''', '''ALTER TABLE "test_rider" ADD CONSTRAINT "test_rider_pony_remote_id_269d66d9_fk_test_pony_remote" FOREIGN KEY ("pony_remote_id") REFERENCES "test_pony" ("remote");''' ], sqls) + + @postgres_fixture() + def test_add_json(self): + from django_redshift_backend.base import DatabaseWrapper + + new_state = self.set_up_test_model('test') + operations = [ + migrations.AddField( + model_name='Pony', + name='structure', + field=models.JSONField( + verbose_name='json data', + null=False, + default={"key1": "value", "key2": 1}, + ), + ), + ] + + with self.collect_sql() as sqls: + self.apply_operations('test', new_state, operations) + + data_type = DatabaseWrapper.data_types['JSONField'] + default = """DEFAULT '{"key1": "value", "key2": 1}'""" + + self.assertEqual([ + f'''ALTER TABLE "test_pony" ADD COLUMN "structure" {data_type} {default} NOT NULL;''', + ], sqls)