Repository: django/django
File: django/db/models/expressions.py (Python)

Code before:
        return self.output_field.get_lookup(lookup)

    def get_transform(self, name):
        return self.output_field.get_transform(name)

    def relabeled_clone(self, change_map):
        clone = self.copy()
        clone.set_source_expressions(
            [
                e.relabeled_clone(change_map) if e is not None else None
                for e in self.get_source_expressions()
            ]
        )
        return clone

    def replace_expressions(self, replacements):
        if not replacements:
            return self
        if replacement := replacements.get(self):
            return replacement
        if not (source_expressions := self.get_source_expressions()):
            return self
        clone = self.copy()
        clone.set_source_expressions(
            [
                expr.replace_expressions(replacements) if expr else None
                for expr in source_expressions
            ]
        )
        return clone

    def get_refs(self):
        refs = set()
        for expr in self.get_source_expressions():
            if expr is None:
                continue
            refs |= expr.get_refs()
        return refs

    def copy(self):
        return copy.copy(self)

    def prefix_references(self, prefix):
        clone = self.copy()
        clone.set_source_expressions(
            [
                (
                    F(f"{prefix}{expr.name}")
                    if isinstance(expr, F)
                    else expr.prefix_references(prefix)
                )

Review comment (suggestion):
As mentionned in the commit message this would have caused objects such as `QuerySet` to be evaluated as replacement as well (since `QuerySet.__bool__` executes the query).

Code after:
        return self.output_field.get_lookup(lookup)

    def get_transform(self, name):
        return self.output_field.get_transform(name)

    def relabeled_clone(self, change_map):
        clone = self.copy()
        clone.set_source_expressions(
            [
                e.relabeled_clone(change_map) if e is not None else None
                for e in self.get_source_expressions()
            ]
        )
        return clone

    def replace_expressions(self, replacements):
        if not replacements:
            return self
        if replacement := replacements.get(self):
            return replacement
        if not (source_expressions := self.get_source_expressions()):
            return self
        clone = self.copy()
        clone.set_source_expressions(
            [
                None if expr is None else expr.replace_expressions(replacements)
                for expr in source_expressions
            ]
        )
        return clone

    def get_refs(self):
        refs = set()
        for expr in self.get_source_expressions():
            if expr is None:
                continue
            refs |= expr.get_refs()
        return refs

    def copy(self):
        return copy.copy(self)

    def prefix_references(self, prefix):
        clone = self.copy()
        clone.set_source_expressions(
            [
                (
                    F(f"{prefix}{expr.name}")
                    if isinstance(expr, F)
                    else expr.prefix_references(prefix)
                )