#35167: JSONFIeld get_db_prep_value being called with `Cast` types
---------------------------------+------------------------------------
     Reporter:  Samantha Hughes  |                    Owner:  (none)
         Type:  Bug              |                   Status:  new
    Component:  Error reporting  |                  Version:  4.2
     Severity:  Normal           |               Resolution:
     Keywords:  JSONField        |             Triage Stage:  Accepted
    Has patch:  0                |      Needs documentation:  0
  Needs tests:  0                |  Patch needs improvement:  0
Easy pickings:  0                |                    UI/UX:  0
---------------------------------+------------------------------------
Comment (by Simon Charette):

 You mentioned that you are using Django 4.2 so the following patch won't
 apply cleanly against your branch but against main it gets the tests
 passing

 {{{#!diff
 diff --git a/django/db/models/fields/json.py
 b/django/db/models/fields/json.py
 index 571e6e79f3..73b4a4dd50 100644
 --- a/django/db/models/fields/json.py
 +++ b/django/db/models/fields/json.py
 @@ -99,18 +99,23 @@ def get_internal_type(self):
      def get_db_prep_value(self, value, connection, prepared=False):
          if not prepared:
              value = self.get_prep_value(value)
 -        if isinstance(value, expressions.Value) and isinstance(
 -            value.output_field, JSONField
 -        ):
 -            value = value.value
 -        elif hasattr(value, "as_sql"):
 -            return value
          return connection.ops.adapt_json_value(value, self.encoder)

      def get_db_prep_save(self, value, connection):
 +        # This slightly convoluted logic is to allow for `None` to be
 used to
 +        # store SQL `NULL` while `Value(None, JSONField())` can be used
 to
 +        # store JSON `null` while preventing compilable `as_sql` values
 from
 +        # making their way to `get_db_prep_value` which is what the
 `super()`
 +        # implementation does.
          if value is None:
              return value
 -        return self.get_db_prep_value(value, connection)
 +        elif (
 +            isinstance(value, expressions.Value)
 +            and value.value is None
 +            and isinstance(value.output_field, JSONField)
 +        ):
 +            value = None
 +        return super().get_db_prep_save(value, connection)

      def get_transform(self, name):
          transform = super().get_transform(name)
 }}}

 Basically now that the deprecation shims have been removed the logic can
 be slightly simplified to only have to special case the `Value(None,
 JSONField())` which is truly the only problematic case in the
 implementation of `JSONField` due to ambiguous nature of `None` with
 regards to SQL `NULL` and JSON `null`.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/35167#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018d7c9d2f39-246340ce-af48-4156-a2df-f60361f10c90-000000%40eu-central-1.amazonses.com.

Reply via email to