Opened 3 months ago
Last modified 8 days ago
#35659 assigned Cleanup/optimization
Document db_default behaviour before instances are saved
Reported by: | Markus Andresen | Owned by: | Jerome Cagado |
---|---|---|---|
Component: | Documentation | Version: | 5.0 |
Severity: | Normal | Keywords: | db_default |
Cc: | Ülgen Sarıkavak | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
There seems to be an unexpected behavior when using the db_default attribute on a BooleanField. The bool() evaluation when the instance is not saved to the database does not reflect the specified db_default value.
Steps to Reproduce:
from django.db import models class MyModel(models.Model): my_field = models.BooleanField(db_default=False) my_obj = MyModel() bool(my_obj.my_field) # True, which is unexpected. my_obj.save() bool(my_obj.my_field) # False, as expected.
I know this can be worked around by adding a default attribute in addition to db_default, but in my opinion its not clear enough from the documentation that you have to.
Change History (6)
comment:1 by , 3 months ago
Component: | Database layer (models, ORM) → Documentation |
---|---|
Summary: | Unexpected Behavior(footgun) with db_default on a BooleanField → Document db_default behaviour before instances are saved |
Triage Stage: | Unreviewed → Accepted |
Type: | Uncategorized → Cleanup/optimization |
comment:2 by , 3 months ago
Hello, I would like to take a shot on this issue as a new contributor. Could you please assign it to me? Thanks!
comment:3 by , 3 months ago
Has patch: | set |
---|---|
Owner: | set to |
Status: | new → assigned |
Hi team,
I’ve submitted a pull request to address this issue. You can review the changes here: https://github.com/django/django/pull/18454
Please let me know if there are any further updates needed.
Thanks!
comment:4 by , 3 months ago
Hey, thanks for accepting the ticket!
It's not safe to randomly cast things without at least checking what the underlying type of the variable is. Eg bool("false") == True. In this case my_field is an instance of DatabaseDefault.
I'm aware, the reason this behaviour is problematic (if not properly documented) is because my_field
is assumed to be a bool since that is the case when a BooleanField has a default
attribute, would people assume that db_default
behaves differently? They might have code that looks something like this:
my_model = MyModel if MyModel.my_field: do_something # later in code my_model.save()
Docs currently looks like this
If both db_default and Field.default are set, default will take precedence when creating instances in Python code. db_default will still be set at the database level and will be used when inserting rows outside of the ORM or when adding a new field in a migration.
default taking precedence in Python code
is somewhat misleading IMO, adding a proper "disclaimer" here might be good?
comment:5 by , 3 months ago
Patch needs improvement: | set |
---|
comment:6 by , 8 days ago
Cc: | added |
---|
Thanks for the report, though I disagree with the analysis of it being unexpected 😊
It's not safe to randomly cast things without at least checking what the underlying type of the variable is. Eg
bool("false") == True
. In this casemy_field
is an instance ofDatabaseDefault
.The documentation of
DatabaseDefault
is missing. The docs could probably be improved to make mention of it and that field values will be of this type before saving to the database.Accepting the ticket as a docs improvement 👍