summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorGagaro <gagaro42@gmail.com>2022-01-31 16:04:13 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-05-10 11:22:23 +0200
commit667105877e6723c6985399803a364848891513cc (patch)
treeb6b3a9fe9f2c8767bc6f6a68f0580eef021b2b55 /docs
parent441103a04d1d167dc870eaaf90e3fba974f67c93 (diff)
Fixed #30581 -- Added support for Meta.constraints validation.
Thanks Simon Charette, Keryn Knight, and Mariusz Felisiak for reviews.
Diffstat (limited to 'docs')
-rw-r--r--docs/ref/checks.txt2
-rw-r--r--docs/ref/contrib/postgres/constraints.txt19
-rw-r--r--docs/ref/models/constraints.txt74
-rw-r--r--docs/ref/models/instances.txt59
-rw-r--r--docs/releases/4.1.txt13
5 files changed, 140 insertions, 27 deletions
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index 3228d71f08..233d999fe7 100644
--- a/docs/ref/checks.txt
+++ b/docs/ref/checks.txt
@@ -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
--------
diff --git a/docs/ref/contrib/postgres/constraints.txt b/docs/ref/contrib/postgres/constraints.txt
index 1c283c367e..26c6356693 100644
--- a/docs/ref/contrib/postgres/constraints.txt
+++ b/docs/ref/contrib/postgres/constraints.txt
@@ -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
--------
diff --git a/docs/ref/models/constraints.txt b/docs/ref/models/constraints.txt
index 52bb8b48e0..9b1e110f85 100644
--- a/docs/ref/models/constraints.txt
+++ b/docs/ref/models/constraints.txt
@@ -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>`.
diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt
index e98377b8bf..b3323eaa0e 100644
--- a/docs/ref/models/instances.txt
+++ b/docs/ref/models/instances.txt
@@ -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
==============
diff --git a/docs/releases/4.1.txt b/docs/releases/4.1.txt
index 1bd3fe68b0..fa5990393b 100644
--- a/docs/releases/4.1.txt
+++ b/docs/releases/4.1.txt
@@ -65,6 +65,15 @@ advantage of developments in the ORM's asynchronous support as it evolves.
See :ref:`async-queries` for details and limitations.
+Validation of Constraints
+-------------------------
+
+:class:`Check <django.db.models.CheckConstraint>`,
+:class:`unique <django.db.models.UniqueConstraint>`, and :class:`exclusion
+<django.contrib.postgres.constraints.ExclusionConstraint>` constraints defined
+in the :attr:`Meta.constraints <django.db.models.Options.constraints>` option
+are now checked during :ref:`model validation <validating-objects>`.
+
.. _csrf-cookie-masked-usage:
``CSRF_COOKIE_MASKED`` setting
@@ -551,6 +560,10 @@ Miscellaneous
* The undocumented ``django.contrib.auth.views.SuccessURLAllowedHostsMixin``
mixin is replaced by ``RedirectURLMixin``.
+* :class:`~django.db.models.BaseConstraint` subclasses must implement
+ :meth:`~django.db.models.BaseConstraint.validate` method to allow those
+ constraints to be used for validation.
+
.. _deprecated-features-4.1:
Features deprecated in 4.1