Commit 011abb7d authored by Anubhav Joshi's avatar Anubhav Joshi Committed by Tim Graham
Browse files

Fixed #19671 -- Added warnings that null and validators are ignored for ManyToManyField.

Thanks Loic Bistuer and Tim Graham for help and review.
parent 3a85aae2
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ certain test -- e.g. being a DateField or ForeignKey.
import datetime

from django.db import models
from django.db.models.fields.related import ManyToManyField
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.utils.encoding import smart_text, force_text
from django.utils.translation import ugettext_lazy as _
@@ -207,8 +208,8 @@ class RelatedFieldListFilter(FieldListFilter):
                'display': val,
            }
        if (isinstance(self.field, models.related.RelatedObject) and
                self.field.field.null or hasattr(self.field, 'rel') and
                self.field.null):
                (self.field.field.null or isinstance(self.field.field, ManyToManyField)) or
                hasattr(self.field, 'rel') and (self.field.null or isinstance(self.field, ManyToManyField))):
            yield {
                'selected': bool(self.lookup_val_isnull),
                'query_string': cl.get_query_string({
+26 −0
Original line number Diff line number Diff line
@@ -1899,6 +1899,7 @@ class ManyToManyField(RelatedField):
        errors = super(ManyToManyField, self).check(**kwargs)
        errors.extend(self._check_unique(**kwargs))
        errors.extend(self._check_relationship_model(**kwargs))
        errors.extend(self._check_ignored_options(**kwargs))
        return errors

    def _check_unique(self, **kwargs):
@@ -1913,6 +1914,31 @@ class ManyToManyField(RelatedField):
            ]
        return []

    def _check_ignored_options(self, **kwargs):
        warnings = []

        if self.null:
            warnings.append(
                checks.Warning(
                    'null has no effect on ManyToManyField.',
                    hint=None,
                    obj=self,
                    id='fields.W340',
                )
            )

        if len(self._validators) > 0:
            warnings.append(
                checks.Warning(
                    'ManyToManyField does not support validators.',
                    hint=None,
                    obj=self,
                    id='fields.W341',
                )
            )

        return warnings

    def _check_relationship_model(self, from_model=None, **kwargs):
        if hasattr(self.rel.through, '_meta'):
            qualified_model_name = "%s.%s" % (
+2 −0
Original line number Diff line number Diff line
@@ -148,6 +148,8 @@ Related Fields
* **fields.E338**: The intermediary model ``<through model>`` has no field
  ``<field name>``.
* **fields.E339**: ``<model>.<field name>`` is not a foreign key to ``<model>``.
* **fields.W340**: ``null`` has no effect on ``ManyToManyField``.
* **fields.W341**: ``ManyToManyField`` does not support ``validators``.

Signals
~~~~~~~
+4 −0
Original line number Diff line number Diff line
@@ -1448,6 +1448,10 @@ that control how the relationship functions.

    If in doubt, leave it to its default of ``True``.

:class:`ManyToManyField` does not support :attr:`~Field.validators`.

:attr:`~Field.null` has no effect since there is no way to require a
relationship at the database level.

.. _ref-onetoone:

+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ class Book(models.Model):
    title = models.CharField(max_length=50)
    year = models.PositiveIntegerField(null=True, blank=True)
    author = models.ForeignKey(User, verbose_name="Verbose Author", related_name='books_authored', blank=True, null=True)
    contributors = models.ManyToManyField(User, verbose_name="Verbose Contributors", related_name='books_contributed', blank=True, null=True)
    contributors = models.ManyToManyField(User, verbose_name="Verbose Contributors", related_name='books_contributed', blank=True)
    is_best_seller = models.NullBooleanField(default=0)
    date_registered = models.DateField(null=True)
    no = models.IntegerField(verbose_name='number', blank=True, null=True)  # This field is intentionally 2 characters long. See #16080.
Loading