Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#29549 closed Cleanup/optimization (fixed)

Document that Field.choices are enforced by model validation

Reported by: Evgeny Arshinov Owned by: Tim Graham
Component: Documentation Version: 1.11
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Evgeny Arshinov)

This is basically a sequel of #6967.

For some reason, only form validation was considered in the original ticket, but data validation is not limited to that, but also includes data integrity checks running when one calls model_instance.save().

As a developer, I would expect model_instance.save() to validate the choices field against the list of possible choices, not least because the list is defined at the model level, participates in db migrations etc., so it should take effect on model instances.

I haven't been able to find any documentation or existing bug reports that clearly state that choices argument only affects the corresponding model form field presentation and does not ensure data integrity.

In summary:

  1. I would like to know the rationale for ignoring choices during data integrity checks, in case I am missing something.
  2. Please consider providing an option to turn data integrity check on.
  3. If the current behavior is left intact, it should be explicitly documented in the official documentation.

Change History (10)

comment:1 by Tim Graham, 6 years ago

Did you mean to title the ticket "Model.save() doesn't validate CHOICES"?

This is documented:

Note, however, that like Model.full_clean(), a model’s clean() method is not invoked when you call your model’s save() method.

This is because of backwards compatibility (and probably performance considerations).

There are ways to change the behavior in your project.

in reply to:  1 comment:2 by Evgeny Arshinov, 6 years ago

Description: modified (diff)
Summary: ModelForms doesn't validate CHOICESModel.save() doesn't validate CHOICES

Replying to Tim Graham:

Did you mean to title the ticket "Model.save() doesn't validate CHOICES"?

Yes. Sorry for the incorrect title, I fixed that.

This is documented:

Note, however, that like Model.full_clean(), a model’s clean() method is not invoked when you call your model’s save() method.

OK, I think I did not pay enough attention to the point that saving and validation are two different steps, as documented in the model instance reference, and fields are generally validated during clean() except for explicitly documented cases like unique (which is validated in save()).

However, it seems that many people stumble upon this issue. Maybe an explicit note could be added to the documentation for the choices parameter?

This is because of backwards compatibility (and probably performance considerations).

There are ways to change the behavior in your project.

OK, thank you for the direct link. We will consider using this approach in our project.

comment:3 by Tim Graham, 6 years ago

Component: Database layer (models, ORM)Documentation
Has patch: set
Owner: changed from nobody to Tim Graham
Status: newassigned
Summary: Model.save() doesn't validate CHOICESDocument that Field.choices are enforced by model validation
Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

comment:4 by GitHub <noreply@…>, 6 years ago

Resolution: fixed
Status: assignedclosed

In 8b1d361f:

Fixed #29549 -- Doc'd that Field.choices are enforced by model validation.

comment:5 by Tim Graham <timograham@…>, 6 years ago

In 50dc9fad:

[2.1.x] Fixed #29549 -- Doc'd that Field.choices are enforced by model validation.

Backport of 8b1d361f28c80cb0fa84a3714d711174bd25cdfa from master

comment:6 by Evgeny Arshinov, 6 years ago

Description: modified (diff)

comment:7 by Evgeny Arshinov, 6 years ago

Component: DocumentationDatabase layer (models, ORM)
Has patch: unset
Resolution: fixed
Status: closednew
Summary: Document that Field.choices are enforced by model validationModel.save() doesn't validate CHOICES
Triage Stage: AcceptedUnreviewed
Type: Cleanup/optimizationUncategorized

Guys, I am sorry but I have to reopen the ticket because it turned out that the proposed solution with calling full_clean on pre_save does not work, which means that the original problem is still unsolved. In #29655 I have received a response that performing validation during model save is not a supported scenario.

comment:8 by Tim Graham, 6 years ago

Component: Database layer (models, ORM)Documentation
Resolution: fixed
Status: newclosed
Summary: Model.save() doesn't validate CHOICESDocument that Field.choices are enforced by model validation
Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

Absent some proposal of the changes Django should make (not clear to me), opening a Trac ticket isn't the way to proceed. This ticket has been repurposed for further documentation. If we decide to make some other change, we'll open a new ticket. Feel free to write to the DevelopersMailingList if you have some ideas.

in reply to:  8 comment:9 by Evgeny Arshinov, 6 years ago

Replying to Tim Graham:

Absent some proposal of the changes Django should make (not clear to me), opening a Trac ticket isn't the way to proceed. This ticket has been repurposed for further documentation. If we decide to make some other change, we'll open a new ticket. Feel free to write to the DevelopersMailingList if you have some ideas.

Hello Tim,

I don't have a proposal except starting to support model validation on save. I am not familiar with Django's inner workings to suggest any concrete steps.

However, I am inclined to think that presence of a problem should be enough for a ticket to be opened, whether or not there is a concrete change proposal. The question about incomplete validation comes up fairly regularly i.e. on StackOverflow, and a ticket in the official bug tracker could be a good reference source and an indicator of the fact that Django developers are aware of the problem and maybe fix it someday. Also, a ticket can be subscribed to. I guess I am not the only one who prefers a ticket to numerous disorganized discussions on StackOverflow and other forums.

I understand that what I have written might contradict the code of practice established in Django. If it is so, I am fine with closing the discussion since I have nothing more to suggest.

comment:10 by Tim Graham, 6 years ago

As Simon said in #29655, "Enabling model validation on save is likely to break a few things and degrade performance significantly. I don't think that's a pattern we should encourage or support at this point. Django and third-party applications simply don't expect ValidationError to be thrown on save(), this effectively change the signature of the function."

Thus, a ticket suggesting that would be closed as wontfix unless a discussion on the mailing list reaches a different conclusion.

Note: See TracTickets for help on using tickets.
Back to Top