Skip to content

Commit

Permalink
Fixed #34754 -- Fixed JSONField check constraints validation on NULL …
Browse files Browse the repository at this point in the history
…values.

The __isnull lookup of JSONField must special case
Value(None, JSONField()) left-hand-side in order to be coherent with
its convoluted null handling.

Since psycopg>=3 offers no way to pass a NULL::jsonb the issue is
resolved by optimizing IsNull(Value(None), True | False) to
True | False.

Regression in 5c23d9f.

Thanks Alexandre Collet for the report.
  • Loading branch information
charettes authored and felixxm committed Aug 4, 2023
1 parent 2b58238 commit 3434dbd
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 1 deletion.
5 changes: 5 additions & 0 deletions django/db/models/lookups.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,11 @@ def as_sql(self, compiler, connection):
raise ValueError(
"The QuerySet value for an isnull lookup must be True or False."
)
if isinstance(self.lhs, Value) and self.lhs.value is None:
if self.rhs:
raise FullResultSet
else:
raise EmptyResultSet
sql, params = self.process_lhs(compiler, connection)
if self.rhs:
return "%s IS NULL" % sql, params
Expand Down
4 changes: 3 additions & 1 deletion docs/releases/4.2.5.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ Django 4.2.5 fixes several bugs in 4.2.4.
Bugfixes
========

* ...
* Fixed a regression in Django 4.2 that caused an incorrect validation of
``CheckConstraints`` on ``__isnull`` lookups against ``JSONField``
(:ticket:`34754`).
7 changes: 7 additions & 0 deletions tests/constraints/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,10 @@ class Meta:

class ChildModel(AbstractModel):
pass


class JSONFieldModel(models.Model):
data = models.JSONField(null=True)

class Meta:
required_db_features = {"supports_json_field"}
20 changes: 20 additions & 0 deletions tests/constraints/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .models import (
ChildModel,
ChildUniqueConstraintProduct,
JSONFieldModel,
Product,
UniqueConstraintConditionProduct,
UniqueConstraintDeferrable,
Expand Down Expand Up @@ -332,6 +333,25 @@ def test_validate_nullable_field_with_isnull(self):
)
constraint.validate(Product, Product())

@skipUnlessDBFeature("supports_json_field")
def test_validate_nullable_jsonfield(self):
is_null_constraint = models.CheckConstraint(
check=models.Q(data__isnull=True),
name="nullable_data",
)
is_not_null_constraint = models.CheckConstraint(
check=models.Q(data__isnull=False),
name="nullable_data",
)
is_null_constraint.validate(JSONFieldModel, JSONFieldModel(data=None))
msg = f"Constraint “{is_null_constraint.name}” is violated."
with self.assertRaisesMessage(ValidationError, msg):
is_null_constraint.validate(JSONFieldModel, JSONFieldModel(data={}))
msg = f"Constraint “{is_not_null_constraint.name}” is violated."
with self.assertRaisesMessage(ValidationError, msg):
is_not_null_constraint.validate(JSONFieldModel, JSONFieldModel(data=None))
is_not_null_constraint.validate(JSONFieldModel, JSONFieldModel(data={}))


class UniqueConstraintTests(TestCase):
@classmethod
Expand Down

0 comments on commit 3434dbd

Please sign in to comment.