﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
35149	JSONField db_default requires wrapping values in json.dumps()	David Sanders	Simon Charette	"This caught me out as I was expecting `db_default` to accept the same types as what would be set on model instance fields.

**tl;dr**

This will cause psycopg to raise `ProgrammingError: cannot adapt type 'dict'`

{{{
class Foo(models.Model):
    json = models.JSONField(db_default={""foo"": ""bar""})
}}}

however this works:

{{{
class Foo(models.Model):
    json = models.JSONField(db_default=json.dumps({""foo"": ""bar""}))
}}}

At the very least this may be a doc update but I feel like it violates principle of least astonishment to not use the same type that JSONField attrs use.  If we do decide to make this consistent it seems like `BaseSchemaEditor.db_default_sql()` [1] just needs to be aware of the field's type and adapt it correctly – something like calling `get_db_prep_value()`?

[1] https://github.com/django/django/blob/2005530920e7c290bb1cf7d9ada155250faa81ad/django/db/backends/base/schema.py#L411

**Further details**

Migration generated without json.dumps:

{{{
class Migration(migrations.Migration):
    initial = True

    dependencies = []

    operations = [
        migrations.CreateModel(
            name=""Foo"",
            fields=[
                (
                    ""id"",
                    models.BigAutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name=""ID"",
                    ),
                ),
                (""json"", models.JSONField(db_default=models.Value({""foo"": ""bar""}))),
            ],
        ),
    ]
}}}

Traceback when applying above migration:

{{{
django-sample % dj migrate jsonfield_dbdefault
Operations to perform:
  Apply all migrations: jsonfield_dbdefault
Running migrations:
  Applying jsonfield_dbdefault.0001_initial...Traceback (most recent call last):
  File ""/path/to/projects/django-sample/./manage.py"", line 22, in <module>
    main()
  File ""/path/to/projects/django-sample/./manage.py"", line 18, in main
    execute_from_command_line(sys.argv)
  File ""/path/to/projects/django/django/core/management/__init__.py"", line 442, in execute_from_command_line
    utility.execute()
  File ""/path/to/projects/django/django/core/management/__init__.py"", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File ""/path/to/projects/django/django/core/management/base.py"", line 413, in run_from_argv
    self.execute(*args, **cmd_options)
  File ""/path/to/projects/django/django/core/management/base.py"", line 459, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django/django/core/management/base.py"", line 107, in wrapper
    res = handle_func(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django/django/core/management/commands/migrate.py"", line 356, in handle
    post_migrate_state = executor.migrate(
                         ^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django/django/db/migrations/executor.py"", line 135, in migrate
    state = self._migrate_all_forwards(
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django/django/db/migrations/executor.py"", line 167, in _migrate_all_forwards
    state = self.apply_migration(
            ^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django/django/db/migrations/executor.py"", line 252, in apply_migration
    state = migration.apply(state, schema_editor)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django/django/db/migrations/migration.py"", line 132, in apply
    operation.database_forwards(
  File ""/path/to/projects/django/django/db/migrations/operations/models.py"", line 97, in database_forwards
    schema_editor.create_model(model)
  File ""/path/to/projects/django/django/db/backends/base/schema.py"", line 485, in create_model
    self.execute(sql, params or None)
  File ""/path/to/projects/django/django/db/backends/postgresql/schema.py"", line 46, in execute
    sql = self.connection.ops.compose_sql(str(sql), params)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django/django/db/backends/postgresql/operations.py"", line 193, in compose_sql
    return mogrify(sql, params, self.connection)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django/django/db/backends/postgresql/psycopg_any.py"", line 22, in mogrify
    return ClientCursor(cursor.connection).mogrify(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/client_cursor.py"", line 40, in mogrify
    pgq = self._convert_query(query, params)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/client_cursor.py"", line 79, in _convert_query
    pgq.convert(query, params)
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/_queries.py"", line 213, in convert
    self.dump(vars)
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/_queries.py"", line 223, in dump
    self.params = tuple(
                  ^^^^^^
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/_queries.py"", line 224, in <genexpr>
    self._tx.as_literal(p) if p is not None else b""NULL"" for p in params
    ^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/_transform.py"", line 198, in as_literal
    dumper = self.get_dumper(obj, PY_TEXT)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/_transform.py"", line 245, in get_dumper
    raise ex from None
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/_transform.py"", line 243, in get_dumper
    dcls = self.adapters.get_dumper(key, format)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ""/path/to/projects/django-sample/.direnv/python-3.11/lib/python3.11/site-packages/psycopg/_adapters_map.py"", line 223, in get_dumper
    raise e.ProgrammingError(
psycopg.ProgrammingError: cannot adapt type 'dict' using placeholder '%t' (format: TEXT)
}}}"	Bug	closed	Database layer (models, ORM)	5.0	Release blocker	fixed	JSONField db_default	Simon Charette Lily Foote Carlton Gibson	Ready for checkin	1	0	0	0	0	0
