#34435: JSONField with string default raises fields.E010 warning.
--------------------------------------+------------------------------------
     Reporter:  Tobias Krönke         |                    Owner:  stimver
         Type:  Bug                   |                   Status:  assigned
    Component:  Core (System checks)  |                  Version:  4.1
     Severity:  Normal                |               Resolution:
     Keywords:                        |             Triage Stage:  Accepted
    Has patch:  0                     |      Needs documentation:  0
  Needs tests:  0                     |  Patch needs improvement:  0
Easy pickings:  0                     |                    UI/UX:  0
--------------------------------------+------------------------------------

Comment (by Sage Abdullah):

 Replying to [comment:6 Tobias Krönke]:
 > That's a good question, because python offers no simple check a la
 `ismutable(x)`. It would be easy to just do an additional check like
 `isinstance(x, (bool, int, float, tuple, str, frozenset, decimal, complex,
 bytes))`, if you can live with the "danger" of users sub-classing those
 types and making them mutable. But I guess those can't be helped with this
 check.

 Strict (without subclasses) `isinstance` checking can be done using
 `type(x) in (bool, int, float, tuple, str, ...)`.

 Anyway, I'm convinced this is more of a documentation than an
 implementation issue. I'll explain below. Buckle up, it's story time!

 `JSONField`, `HStoreField`, and `ArrayField` never supported non-callable
 defaults as of https://github.com/django/django/pull/8930, when
 `JSONField` was still `django.contrib.postgres.fields.JSONField`.

 When I started working on the new `django.db.models.JSONField`, I tried
 changing this behaviour to support using non-callable defaults because the
 base [https://docs.djangoproject.com/en/dev/ref/models/fields/#default
 Field.default] documentation (which in theory is applicable to all fields
 in `django.db.models`), says `"The default value for the field. This can
 be a value or a callable object."`.

 Thus, I initially implemented an `isinstance()` check for this (lost in
 time, but remnants can be seen at:
 https://github.com/django/django/pull/11452#discussion_r295674504).

 During the time where this behaviour change was still in the PR, we added
 
[https://github.com/django/django/blob/8b1ff0da4b162e87edebd94e61f2cd153e9e159d/docs/ref/models/fields.txt#L1268-L1272
 the paragraph (quoted in the first comment)] to the documentation for
 `JSONField`'s default, based on a suggestion at:
 https://github.com/django/django/pull/11452#discussion_r306186695

 However, based on the discussion at
 https://github.com/django/django/pull/11452#discussion_r335854274, we
 explicitly decided **to keep not supporting non-callable defaults for
 `JSONField`**. This leads to https://github.com/django/django/pull/11932,
 where `CheckFieldDefaultMixin` is moved to
 `django.db.models.fields.mixins` without any behaviour change (i.e. the
 default **still has to be a callable**).

 The problem is, after that decision was made, we forgot to remove the
 paragraph in the documentation, which is no longer correct. I believe the
 `fields.E010` check message is the correct behaviour here.

 Thus, I propose that we change the documentation instead, from

 > If you give the field a `default`, ensure it's an immutable object, such
 as a `str`, or a callable object that returns a fresh mutable object each
 time, such as `dict` or a function. Providing a mutable default object
 like `default={}` or `default=[]` shares the one object between all model
 instances.

 to something like

 > If you give the field a `default`, ensure it is a callable object that
 returns a fresh object each time, such as `dict` or a function. Providing
 a non-callable default object is not supported because a mutable object
 would be shared between all model instances. There is a system check to
 ensure that the `default` is a callable.

 Maybe wrap it in a `note` or something so that it's more prominent,
 because this deviates from the base `Field.default` behaviour.

 Hope this helps!

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34435#comment:7>
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/01070187958f6cc9-eec71168-9811-48a0-a4f7-d643e6649caf-000000%40eu-central-1.amazonses.com.

Reply via email to