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

Code before:
            [
                (
                    v
                    if hasattr(v, "as_sql")
                    else get_db_prep_value(v, connection, prepared=True)
                )
                for v in value
            ],
        )


class FieldGetDbPrepValueIterableMixin(FieldGetDbPrepValueMixin):
    """
    Some lookups require Field.get_db_prep_value() to be called on each value
    in an iterable.
    """

    get_db_prep_lookup_value_is_iterable = True

    def get_prep_lookup(self):
        if hasattr(self.rhs, "resolve_expression"):
            return self.rhs
        if any(hasattr(value, "resolve_expression") for value in self.rhs):
            return ExpressionList(
                *[
                    (
                        value
                        if hasattr(value, "resolve_expression")
                        else Value(value, self.lhs.output_field)
                    )
                    for value in self.rhs
                ]
            )
        prepared_values = []
        for rhs_value in self.rhs:
            if (
                self.prepare_rhs
                and hasattr(self.lhs, "output_field")
                and hasattr(self.lhs.output_field, "get_prep_value")
            ):
                rhs_value = self.lhs.output_field.get_prep_value(rhs_value)
            prepared_values.append(rhs_value)
        return prepared_values

    def process_rhs(self, compiler, connection):
        if self.rhs_is_direct_value():
            # rhs should be an iterable of values. Use batch_process_rhs()
            # to prepare/transform those values.
            return self.batch_process_rhs(compiler, connection)
        elif isinstance(self.rhs, ExpressionList):
            # rhs contains at least one expression. Unwrap them and delegate

Review comment (suggestion):
We can return early since direct values will be prepped at compilation time by `Value.as_sql()`; there's no need to prep them here.

Code after:
            [
                (
                    v
                    if hasattr(v, "as_sql")
                    else get_db_prep_value(v, connection, prepared=True)
                )
                for v in value
            ],
        )


class FieldGetDbPrepValueIterableMixin(FieldGetDbPrepValueMixin):
    """
    Some lookups require Field.get_db_prep_value() to be called on each value
    in an iterable.
    """

    get_db_prep_lookup_value_is_iterable = True

    def get_prep_lookup(self):
        if hasattr(self.rhs, "resolve_expression"):
            return self.rhs
        if any(hasattr(value, "resolve_expression") for value in self.rhs):
            # Wrap direct values in Value expressions so they are handled by
            # the database at compilation time, along with other expressions.
            return ExpressionList(
                *[
                    (
                        value
                        if hasattr(value, "resolve_expression")
                        else Value(value, self.lhs.output_field)
                    )
                    for value in self.rhs
                ]
            )
        prepared_values = []
        for rhs_value in self.rhs:
            if (
                self.prepare_rhs
                and hasattr(self.lhs, "output_field")
                and hasattr(self.lhs.output_field, "get_prep_value")
            ):
                rhs_value = self.lhs.output_field.get_prep_value(rhs_value)
            prepared_values.append(rhs_value)
        return prepared_values

    def process_rhs(self, compiler, connection):
        if self.rhs_is_direct_value():
            # rhs should be an iterable of values. Use batch_process_rhs()
            # to prepare/transform those values.
            return self.batch_process_rhs(compiler, connection)