Commit 064d4b1c authored by Tim Graham's avatar Tim Graham
Browse files

Fixed #25320 -- Reverted ManyToManyField.null to False for backwards compatibility.

Thanks Tom Christie for the report and review.
parent 4c30fa90
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -176,8 +176,16 @@ class RelatedFieldListFilter(FieldListFilter):
        self.title = self.lookup_title
        self.empty_value_display = model_admin.get_empty_value_display()

    @property
    def include_empty_choice(self):
        """
        Return True if a "(None)" choice should be included, which filters
        out everything except empty relationships.
        """
        return self.field.null or (self.field.is_relation and self.field.many_to_many)

    def has_output(self):
        if self.field.null:
        if self.include_empty_choice:
            extra = 1
        else:
            extra = 0
@@ -204,7 +212,7 @@ class RelatedFieldListFilter(FieldListFilter):
                }, [self.lookup_kwarg_isnull]),
                'display': val,
            }
        if self.field.null:
        if self.include_empty_choice:
            yield {
                'selected': bool(self.lookup_val_isnull),
                'query_string': cl.get_query_string({
+0 −3
Original line number Diff line number Diff line
@@ -2304,8 +2304,6 @@ class ManyToManyField(RelatedField):

        self.db_table = db_table
        self.swappable = swappable
        # Many-to-many fields are always nullable.
        self.null = True

    def check(self, **kwargs):
        errors = super(ManyToManyField, self).check(**kwargs)
@@ -2552,7 +2550,6 @@ class ManyToManyField(RelatedField):
    def deconstruct(self):
        name, path, args, kwargs = super(ManyToManyField, self).deconstruct()
        # Handle the simpler arguments.
        del kwargs["null"]
        if self.db_table is not None:
            kwargs['db_table'] = self.db_table
        if self.remote_field.db_constraint is not True:
+10 −0
Original line number Diff line number Diff line
@@ -523,6 +523,16 @@ class ListFiltersTests(TestCase):
        self.assertEqual(choice['selected'], True)
        self.assertEqual(choice['query_string'], '?books_contributed__id__exact=%d' % self.django_book.pk)

        # With one book, the list filter should appear because there is also a
        # (None) option.
        Book.objects.exclude(pk=self.djangonaut_book.pk).delete()
        filterspec = changelist.get_filters(request)[0]
        self.assertEqual(len(filterspec), 2)
        # With no books remaining, no list filters should appear.
        Book.objects.all().delete()
        filterspec = changelist.get_filters(request)[0]
        self.assertEqual(len(filterspec), 0)

    def test_relatedonlyfieldlistfilter_foreignkey(self):
        modeladmin = BookAdminRelatedOnlyFilter(Book, site)

+6 −0
Original line number Diff line number Diff line
@@ -216,3 +216,9 @@ class FieldFlagsTests(test.SimpleTestCase):
                reverse_field = field.remote_field
                self.assertEqual(field.model, reverse_field.related_model)
                self.assertEqual(field.related_model, reverse_field.model)

    def test_null(self):
        # null isn't well defined for a ManyToManyField, but changing it to
        # True causes backwards compatibility problems (#25320).
        self.assertFalse(AllFieldsModel._meta.get_field('m2m').null)
        self.assertTrue(AllFieldsModel._meta.get_field('reverse2').null)