mirror of
https://github.com/django/django.git
synced 2025-07-24 05:36:15 +00:00
Fixed #30581 -- Added support for Meta.constraints validation.
Thanks Simon Charette, Keryn Knight, and Mariusz Felisiak for reviews.
This commit is contained in:
parent
441103a04d
commit
667105877e
17 changed files with 852 additions and 88 deletions
|
@ -395,6 +395,8 @@ Models
|
|||
* **models.W043**: ``<database>`` does not support indexes on expressions.
|
||||
* **models.W044**: ``<database>`` does not support unique constraints on
|
||||
expressions.
|
||||
* **models.W045**: Check constraint ``<constraint>`` contains ``RawSQL()``
|
||||
expression and won't be validated during the model ``full_clean()``.
|
||||
|
||||
Security
|
||||
--------
|
||||
|
|
|
@ -12,7 +12,7 @@ PostgreSQL supports additional data integrity constraints available from the
|
|||
``ExclusionConstraint``
|
||||
=======================
|
||||
|
||||
.. class:: ExclusionConstraint(*, name, expressions, index_type=None, condition=None, deferrable=None, include=None, opclasses=())
|
||||
.. class:: ExclusionConstraint(*, name, expressions, index_type=None, condition=None, deferrable=None, include=None, opclasses=(), violation_error_message=None)
|
||||
|
||||
Creates an exclusion constraint in the database. Internally, PostgreSQL
|
||||
implements exclusion constraints using indexes. The default index type is
|
||||
|
@ -27,6 +27,14 @@ PostgreSQL supports additional data integrity constraints available from the
|
|||
:exc:`~django.db.IntegrityError` is raised. Similarly, when update
|
||||
conflicts with an existing row.
|
||||
|
||||
Exclusion constraints are checked during the :ref:`model validation
|
||||
<validating-objects>`.
|
||||
|
||||
.. versionchanged:: 4.1
|
||||
|
||||
In older versions, exclusion constraints were not checked during model
|
||||
validation.
|
||||
|
||||
``name``
|
||||
--------
|
||||
|
||||
|
@ -165,6 +173,15 @@ creates an exclusion constraint on ``circle`` using ``circle_ops``.
|
|||
:class:`OpClass() <django.contrib.postgres.indexes.OpClass>` in
|
||||
:attr:`~ExclusionConstraint.expressions`.
|
||||
|
||||
``violation_error_message``
|
||||
---------------------------
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
The error message used when ``ValidationError`` is raised during
|
||||
:ref:`model validation <validating-objects>`. Defaults to
|
||||
:attr:`.BaseConstraint.violation_error_message`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
|
|
|
@ -31,24 +31,21 @@ option.
|
|||
|
||||
.. admonition:: Validation of Constraints
|
||||
|
||||
In general constraints are **not** checked during ``full_clean()``, and do
|
||||
not raise ``ValidationError``\s. Rather you'll get a database integrity
|
||||
error on ``save()``. ``UniqueConstraint``\s without a
|
||||
:attr:`~UniqueConstraint.condition` (i.e. non-partial unique constraints)
|
||||
and :attr:`~UniqueConstraint.expressions` (i.e. non-functional unique
|
||||
constraints) are different in this regard, in that they leverage the
|
||||
existing ``validate_unique()`` logic, and thus enable two-stage validation.
|
||||
In addition to ``IntegrityError`` on ``save()``, ``ValidationError`` is
|
||||
also raised during model validation when the ``UniqueConstraint`` is
|
||||
violated.
|
||||
Constraints are checked during the :ref:`model validation
|
||||
<validating-objects>`.
|
||||
|
||||
.. versionchanged:: 4.1
|
||||
|
||||
In older versions, constraints were not checked during model validation.
|
||||
|
||||
``BaseConstraint``
|
||||
==================
|
||||
|
||||
.. class:: BaseConstraint(name)
|
||||
.. class:: BaseConstraint(name, violation_error_message=None)
|
||||
|
||||
Base class for all constraints. Subclasses must implement
|
||||
``constraint_sql()``, ``create_sql()``, and ``remove_sql()`` methods.
|
||||
``constraint_sql()``, ``create_sql()``, ``remove_sql()`` and
|
||||
``validate()`` methods.
|
||||
|
||||
All constraints have the following parameters in common:
|
||||
|
||||
|
@ -60,10 +57,37 @@ All constraints have the following parameters in common:
|
|||
The name of the constraint. You must always specify a unique name for the
|
||||
constraint.
|
||||
|
||||
``violation_error_message``
|
||||
---------------------------
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
.. attribute:: BaseConstraint.violation_error_message
|
||||
|
||||
The error message used when ``ValidationError`` is raised during
|
||||
:ref:`model validation <validating-objects>`. Defaults to
|
||||
``"Constraint “%(name)s” is violated."``.
|
||||
|
||||
``validate()``
|
||||
--------------
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
.. method:: BaseConstraint.validate(model, instance, exclude=None, using=DEFAULT_DB_ALIAS)
|
||||
|
||||
Validates that the constraint, defined on ``model``, is respected on the
|
||||
``instance``. This will do a query on the database to ensure that the
|
||||
constraint is respected. If fields in the ``exclude`` list are needed to
|
||||
validate the constraint, the constraint is ignored.
|
||||
|
||||
Raise a ``ValidationError`` if the constraint is violated.
|
||||
|
||||
This method must be implemented by a subclass.
|
||||
|
||||
``CheckConstraint``
|
||||
===================
|
||||
|
||||
.. class:: CheckConstraint(*, check, name)
|
||||
.. class:: CheckConstraint(*, check, name, violation_error_message=None)
|
||||
|
||||
Creates a check constraint in the database.
|
||||
|
||||
|
@ -78,10 +102,14 @@ specifies the check you want the constraint to enforce.
|
|||
For example, ``CheckConstraint(check=Q(age__gte=18), name='age_gte_18')``
|
||||
ensures the age field is never less than 18.
|
||||
|
||||
.. versionchanged:: 4.1
|
||||
|
||||
The ``violation_error_message`` argument was added.
|
||||
|
||||
``UniqueConstraint``
|
||||
====================
|
||||
|
||||
.. class:: UniqueConstraint(*expressions, fields=(), name=None, condition=None, deferrable=None, include=None, opclasses=())
|
||||
.. class:: UniqueConstraint(*expressions, fields=(), name=None, condition=None, deferrable=None, include=None, opclasses=(), violation_error_message=None)
|
||||
|
||||
Creates a unique constraint in the database.
|
||||
|
||||
|
@ -203,3 +231,21 @@ For example::
|
|||
creates a unique index on ``username`` using ``varchar_pattern_ops``.
|
||||
|
||||
``opclasses`` are ignored for databases besides PostgreSQL.
|
||||
|
||||
``violation_error_message``
|
||||
---------------------------
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
.. attribute:: UniqueConstraint.violation_error_message
|
||||
|
||||
The error message used when ``ValidationError`` is raised during
|
||||
:ref:`model validation <validating-objects>`. Defaults to
|
||||
:attr:`.BaseConstraint.violation_error_message`.
|
||||
|
||||
This message is *not used* for :class:`UniqueConstraint`\s with
|
||||
:attr:`~UniqueConstraint.fields` and without a
|
||||
:attr:`~UniqueConstraint.condition`. Such :class:`~UniqueConstraint`\s show the
|
||||
same message as constraints defined with
|
||||
:attr:`.Field.unique` or in
|
||||
:attr:`Meta.unique_together <django.db.models.Options.constraints>`.
|
||||
|
|
|
@ -198,9 +198,10 @@ There are three steps involved in validating a model:
|
|||
1. Validate the model fields - :meth:`Model.clean_fields()`
|
||||
2. Validate the model as a whole - :meth:`Model.clean()`
|
||||
3. Validate the field uniqueness - :meth:`Model.validate_unique()`
|
||||
4. Validate the constraints - :meth:`Model.validate_constraints`
|
||||
|
||||
All three steps are performed when you call a model's
|
||||
:meth:`~Model.full_clean()` method.
|
||||
All four steps are performed when you call a model's :meth:`~Model.full_clean`
|
||||
method.
|
||||
|
||||
When you use a :class:`~django.forms.ModelForm`, the call to
|
||||
:meth:`~django.forms.Form.is_valid()` will perform these validation steps for
|
||||
|
@ -210,12 +211,18 @@ need to call a model's :meth:`~Model.full_clean()` method if you plan to handle
|
|||
validation errors yourself, or if you have excluded fields from the
|
||||
:class:`~django.forms.ModelForm` that require validation.
|
||||
|
||||
.. method:: Model.full_clean(exclude=None, validate_unique=True)
|
||||
.. versionchanged:: 4.1
|
||||
|
||||
This method calls :meth:`Model.clean_fields()`, :meth:`Model.clean()`, and
|
||||
:meth:`Model.validate_unique()` (if ``validate_unique`` is ``True``), in that
|
||||
order and raises a :exc:`~django.core.exceptions.ValidationError` that has a
|
||||
``message_dict`` attribute containing errors from all three stages.
|
||||
In older versions, constraints were not checked during the model
|
||||
validation.
|
||||
|
||||
.. method:: Model.full_clean(exclude=None, validate_unique=True, validate_constraints=True)
|
||||
|
||||
This method calls :meth:`Model.clean_fields()`, :meth:`Model.clean()`,
|
||||
:meth:`Model.validate_unique()` (if ``validate_unique`` is ``True``), and
|
||||
:meth:`Model.validate_constraints()` (if ``validate_constraints`` is ``True``)
|
||||
in that order and raises a :exc:`~django.core.exceptions.ValidationError` that
|
||||
has a ``message_dict`` attribute containing errors from all four stages.
|
||||
|
||||
The optional ``exclude`` argument can be used to provide a list of field names
|
||||
that can be excluded from validation and cleaning.
|
||||
|
@ -238,6 +245,10 @@ models. For example::
|
|||
|
||||
The first step ``full_clean()`` performs is to clean each individual field.
|
||||
|
||||
.. versionchanged:: 4.1
|
||||
|
||||
The ``validate_constraints`` argument was added.
|
||||
|
||||
.. method:: Model.clean_fields(exclude=None)
|
||||
|
||||
This method will validate all fields on your model. The optional ``exclude``
|
||||
|
@ -306,7 +317,7 @@ pass a dictionary mapping field names to errors::
|
|||
'pub_date': ValidationError(_('Invalid date.'), code='invalid'),
|
||||
})
|
||||
|
||||
Finally, ``full_clean()`` will check any unique constraints on your model.
|
||||
Then, ``full_clean()`` will check unique constraints on your model.
|
||||
|
||||
.. admonition:: How to raise field-specific validation errors if those fields don't appear in a ``ModelForm``
|
||||
|
||||
|
@ -339,16 +350,40 @@ Finally, ``full_clean()`` will check any unique constraints on your model.
|
|||
|
||||
.. method:: Model.validate_unique(exclude=None)
|
||||
|
||||
This method is similar to :meth:`~Model.clean_fields`, but validates all
|
||||
uniqueness constraints on your model instead of individual field values. The
|
||||
optional ``exclude`` argument allows you to provide a list of field names to
|
||||
exclude from validation. It will raise a
|
||||
This method is similar to :meth:`~Model.clean_fields`, but validates
|
||||
uniqueness constraints defined via :attr:`.Field.unique`,
|
||||
:attr:`.Field.unique_for_date`, :attr:`.Field.unique_for_month`,
|
||||
:attr:`.Field.unique_for_year`, or :attr:`Meta.unique_together
|
||||
<django.db.models.Options.unique_together>` on your model instead of individual
|
||||
field values. The optional ``exclude`` argument allows you to provide a list of
|
||||
field names to exclude from validation. It will raise a
|
||||
:exc:`~django.core.exceptions.ValidationError` if any fields fail validation.
|
||||
|
||||
:class:`~django.db.models.UniqueConstraint`\s defined in the
|
||||
:attr:`Meta.constraints <django.db.models.Options.constraints>` are validated
|
||||
by :meth:`Model.validate_constraints`.
|
||||
|
||||
Note that if you provide an ``exclude`` argument to ``validate_unique()``, any
|
||||
:attr:`~django.db.models.Options.unique_together` constraint involving one of
|
||||
the fields you provided will not be checked.
|
||||
|
||||
Finally, ``full_clean()`` will check any other constraints on your model.
|
||||
|
||||
.. versionchanged:: 4.1
|
||||
|
||||
In older versions, :class:`~django.db.models.UniqueConstraint`\s were
|
||||
validated by ``validate_unique()``.
|
||||
|
||||
.. method:: Model.validate_constraints(exclude=None)
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
This method validates all constraints defined in
|
||||
:attr:`Meta.constraints <django.db.models.Options.constraints>`. The
|
||||
optional ``exclude`` argument allows you to provide a list of field names to
|
||||
exclude from validation. It will raise a
|
||||
:exc:`~django.core.exceptions.ValidationError` if any constraints fail
|
||||
validation.
|
||||
|
||||
Saving objects
|
||||
==============
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue