Skip to content

Commit 8d53a3b

Browse files
Fix invalid SQL on DELETE with backward relations/joins
1 parent ff7ef94 commit 8d53a3b

1 file changed

Lines changed: 41 additions & 4 deletions

File tree

tortoise/queryset.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,18 +1428,55 @@ def __init__(
14281428

14291429
def _make_query(self) -> None:
14301430
self.query = copy(self.model._meta.basequery)
1431-
if self.capabilities.support_update_limit_order_by and self._limit:
1432-
self.query._limit = self.query._wrapper_cls(self._limit)
1431+
self.resolve_filters()
1432+
1433+
# If joins are detected, rewrite into an IN subquery to avoid JOINs in DELETE
1434+
if self._joined_tables:
1435+
pk_column = self.model._meta.db_pk_column
1436+
1437+
# Create a pristine, completely separate SELECT query builder
1438+
subquery = self._db.query_class.from_(self.model._meta.basetable).select(
1439+
self.model._meta.basetable[pk_column]
1440+
)
1441+
1442+
# Transfer the resolved wheres and havings criteria from our filter resolution
1443+
subquery._wheres = self.query._wheres
1444+
subquery._havings = self.query._havings
1445+
1446+
# Apply joins directly to the subquery builder
1447+
subquery._joins = self.query._joins
1448+
1449+
# Re-apply limits and sorting to the subquery if needed
1450+
if self._limit:
1451+
subquery._limit = subquery._wrapper_cls(self._limit)
1452+
14331453
self.resolve_ordering(
14341454
model=self.model,
14351455
table=self.model._meta.basetable,
14361456
orderings=self._orderings,
14371457
annotations=self._annotations,
14381458
)
1439-
self.resolve_filters()
1459+
subquery._orderbys = self.query._orderbys
1460+
1461+
# Reconstruct clean pristine delete statement pointing to our subquery
1462+
self.query = copy(self.model._meta.basequery)
1463+
self.query = self.query.where(
1464+
self.model._meta.basetable[pk_column].isin(subquery)
1465+
)
1466+
else:
1467+
# Traditional optimization path if no backward relations/joins exist
1468+
if self.capabilities.support_update_limit_order_by and self._limit:
1469+
self.query._limit = self.query._wrapper_cls(self._limit)
1470+
self.resolve_ordering(
1471+
model=self.model,
1472+
table=self.model._meta.basetable,
1473+
orderings=self._orderings,
1474+
annotations=self._annotations,
1475+
)
1476+
14401477
self.query._delete_from = True
14411478
return
1442-
1479+
14431480
def __await__(self) -> Generator[Any, None, int]:
14441481
self._choose_db_if_not_chosen(True)
14451482
self._make_query()

0 commit comments

Comments
 (0)