Ticket #20535: #20353-Unnecessary_join created for intermediate_table_between_two_M2M_tables.diff

File #20353-Unnecessary_join created for intermediate_table_between_two_M2M_tables.diff, 3.5 KB (added by Kronuz, 2 years ago)

Patch with tests

  • django/db/models/fields/related.py

    class ManyToOneRel(ForeignObjectRel): 
    884884    def set_field_name(self):
    885885        self.field_name = self.field_name or self.to._meta.pk.name
    886886
     887    @property
     888    def related_fields(self):
     889        return [tuple([self.get_related_field(), self.field])]
     890
     891    @property
     892    def foreign_related_fields(self):
     893        return tuple([self.field])
     894
    887895
    888896class OneToOneRel(ManyToOneRel):
    889897    def __init__(self, field, to, field_name, related_name=None, limit_choices_to=None,
  • django/db/models/sql/query.py

    diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
    index 0a41525..492120c 100644
    class Query(object): 
    13561356        # Then, add the path to the query's joins. Note that we can't trim
    13571357        # joins at this stage - we will need the information about join type
    13581358        # of the trimmed joins.
     1359        last = None
     1360        final_path = []
    13591361        for pos, join in enumerate(path):
    1360             opts = join.to_opts
     1362            if pos < len(path) - 1:
     1363                next = path[pos + 1]
     1364            else:
     1365                next = None
    13611366            if join.direct:
    13621367                nullable = self.is_nullable(join.join_field)
    13631368            else:
    13641369                nullable = True
    1365             connection = alias, opts.db_table, join.join_field.get_joining_columns()
     1370            final_path.append(join)
     1371            joining_columns = join.join_field.get_joining_columns()
     1372            if last and next:
     1373                # Try removing previous join if the current one maps directly
     1374                # to the next one (much in the way trim_joins does it):
     1375                cur_targets = set(t.column for t in zip(*join.join_field.related_fields)[0])
     1376                join_targets = set(t.column for t in next.join_field.foreign_related_fields)
     1377                if cur_targets.issubset(join_targets):
     1378                    self.unref_alias(joins.pop())
     1379                    alias = joins[-1]
     1380                    final_path.pop()
     1381                    from_join = joining_columns[0][1]
     1382                    to_join = next.join_field.get_joining_columns()[0][0]
     1383                    joining_columns = ((from_join, to_join),)
     1384            last = join
     1385            opts = join.to_opts
     1386            connection = alias, opts.db_table, joining_columns
    13661387            reuse = can_reuse if join.m2m else None
    13671388            alias = self.join(connection, reuse=reuse,
    13681389                              nullable=nullable, join_field=join.join_field)
    13691390            joins.append(alias)
    13701391        if hasattr(final_field, 'field'):
    13711392            final_field = final_field.field
    1372         return final_field, targets, opts, joins, path
     1393        return final_field, targets, opts, joins, final_path
    13731394
    13741395    def trim_joins(self, targets, joins, path):
    13751396        """
  • tests/m2m_through/tests.py

    diff --git a/tests/m2m_through/tests.py b/tests/m2m_through/tests.py
    index 259dc68..bbf7595 100644
    class M2mThroughTests(TestCase): 
    343343            ],
    344344            attrgetter("name")
    345345        )
     346
     347    def test_ticket_20535_join_trimming(self):
     348        qs = Friendship.objects.filter(first__rel_to_set__first__id=1)
     349        self.assertEqual(str(qs.query).count('JOIN'), 1)
     350
     351    def test_ticket_20535_no_join_trimming(self):
     352        qs = Friendship.objects.filter(first__rel_to_set__first__id=1, first__name='Jane')
     353        self.assertEqual(str(qs.query).count('JOIN'), 2)
Back to Top