v0.163.0
   1"""
   2The main QuerySet implementation. This provides the public API for the ORM.
   3"""
   4
   5from __future__ import annotations
   6
   7import copy
   8import operator
   9import warnings
  10from collections.abc import Callable, Iterator, Sequence
  11from functools import cached_property
  12from itertools import islice
  13from typing import TYPE_CHECKING, Any, Never, Self, overload
  14
  15import plain.runtime
  16import psycopg
  17from plain.exceptions import ValidationError
  18from plain.postgres import transaction
  19from plain.postgres.constants import LOOKUP_SEP, OnConflict
  20from plain.postgres.db import (
  21    PLAIN_VERSION_PICKLE_KEY,
  22    get_connection,
  23)
  24from plain.postgres.exceptions import (
  25    FieldDoesNotExist,
  26    FieldError,
  27    ObjectDoesNotExist,
  28)
  29from plain.postgres.expressions import Case, F, ResolvableExpression, Value, When
  30from plain.postgres.fields import (
  31    Field,
  32    PrimaryKeyField,
  33)
  34from plain.postgres.functions import Cast
  35from plain.postgres.query_utils import Q
  36from plain.postgres.sql import (
  37    AND,
  38    CURSOR,
  39    OR,
  40    DeleteQuery,
  41    InsertQuery,
  42    Query,
  43    RawQuery,
  44    UpdateQuery,
  45)
  46from plain.postgres.utils import resolve_callables
  47from plain.utils.functional import partition
  48
  49# Re-exports for public API
  50__all__ = ["F", "Prefetch", "Q", "QuerySet", "RawQuerySet"]
  51
  52if TYPE_CHECKING:
  53    from plain.postgres import Model
  54
  55# The maximum number of results to fetch in a get() query.
  56MAX_GET_RESULTS = 21
  57
  58# The maximum number of items to display in a QuerySet.__repr__
  59REPR_OUTPUT_SIZE = 20
  60
  61
  62class BaseIterable:
  63    def __init__(
  64        self,
  65        queryset: QuerySet[Any],
  66        chunked_fetch: bool = False,
  67    ):
  68        self.queryset = queryset
  69        self.chunked_fetch = chunked_fetch
  70
  71    def __iter__(self) -> Iterator[Any]:
  72        raise NotImplementedError(
  73            "subclasses of BaseIterable must provide an __iter__() method"
  74        )
  75
  76
  77class ModelIterable(BaseIterable):
  78    """Iterable that yields a model instance for each row."""
  79
  80    def __iter__(self) -> Iterator[Model]:
  81        queryset = self.queryset
  82        compiler = queryset.sql_query.get_compiler()
  83        # Execute the query. This will also fill compiler.select, klass_info,
  84        # and annotations.
  85        results = compiler.execute_sql(chunked_fetch=self.chunked_fetch)
  86        select, klass_info, annotation_col_map = (
  87            compiler.select,
  88            compiler.klass_info,
  89            compiler.annotation_col_map,
  90        )
  91        # These are set by execute_sql() above
  92        assert select is not None
  93        assert klass_info is not None
  94        model_cls = klass_info["model"]
  95        select_fields = klass_info["select_fields"]
  96        model_fields_start, model_fields_end = select_fields[0], select_fields[-1] + 1
  97        init_list = [
  98            f[0].target.name for f in select[model_fields_start:model_fields_end]
  99        ]
 100        related_populators = get_related_populators(klass_info, select)
 101        known_related_objects = [
 102            (
 103                field,
 104                related_objs,
 105                # The raw key value, not the related object the descriptor
 106                # would return -- the dict below is keyed by raw key.
 107                field.value_from_object,
 108            )
 109            for field, related_objs in queryset._known_related_objects.items()
 110        ]
 111        for row in compiler.results_iter(results):
 112            obj = model_cls.from_db(init_list, row[model_fields_start:model_fields_end])
 113            for rel_populator in related_populators:
 114                rel_populator.populate(row, obj)
 115            if annotation_col_map:
 116                for attr_name, col_pos in annotation_col_map.items():
 117                    setattr(obj, attr_name, row[col_pos])
 118
 119            # Add the known related objects to the model.
 120            for field, rel_objs, rel_getter in known_related_objects:
 121                # Avoid overwriting objects loaded by, e.g., select_related().
 122                if field.is_cached(obj):
 123                    continue
 124                rel_obj_id = rel_getter(obj)
 125                try:
 126                    rel_obj = rel_objs[rel_obj_id]
 127                except KeyError:
 128                    pass  # May happen in qs1 | qs2 scenarios.
 129                else:
 130                    setattr(obj, field.name, rel_obj)
 131
 132            yield obj
 133
 134
 135class RawModelIterable(BaseIterable):
 136    """
 137    Iterable that yields a model instance for each row from a raw queryset.
 138    """
 139
 140    queryset: RawQuerySet
 141
 142    def __iter__(self) -> Iterator[Model]:
 143        from plain.postgres.sql.compiler import apply_converters, get_converters
 144
 145        query = self.queryset.sql_query
 146        connection = get_connection()
 147        query_iterator: Iterator[Any] = iter(query)
 148
 149        try:
 150            (
 151                model_init_names,
 152                model_init_pos,
 153                annotation_fields,
 154            ) = self.queryset.resolve_model_init_order()
 155            model_cls = self.queryset.model
 156            assert model_cls is not None
 157            if "id" not in model_init_names:
 158                raise FieldDoesNotExist("Raw query must include the primary key")
 159            fields = [self.queryset.model_fields.get(c) for c in self.queryset.columns]
 160            converters = get_converters(
 161                [
 162                    f.get_col(f.model.model_options.db_table) if f else None
 163                    for f in fields
 164                ],
 165                connection,
 166            )
 167            if converters:
 168                query_iterator = apply_converters(
 169                    query_iterator, converters, connection
 170                )
 171            for values in query_iterator:
 172                # Associate fields to values
 173                model_init_values = [values[pos] for pos in model_init_pos]
 174                instance = model_cls.from_db(model_init_names, model_init_values)
 175                if annotation_fields:
 176                    for column, pos in annotation_fields:
 177                        setattr(instance, column, values[pos])
 178                yield instance
 179        finally:
 180            # Done iterating the Query. If it has its own cursor, close it.
 181            if hasattr(query, "cursor") and query.cursor:
 182                query.cursor.close()
 183
 184
 185class ValuesIterable(BaseIterable):
 186    """
 187    Iterable returned by QuerySet.values() that yields a dict for each row.
 188    """
 189
 190    def __iter__(self) -> Iterator[dict[str, Any]]:
 191        queryset = self.queryset
 192        query = queryset.sql_query
 193        compiler = query.get_compiler()
 194
 195        names = [
 196            *query.values_select,
 197            *query.annotation_select,
 198        ]
 199        indexes = range(len(names))
 200        for row in compiler.results_iter(chunked_fetch=self.chunked_fetch):
 201            yield {names[i]: row[i] for i in indexes}
 202
 203
 204class ValuesListIterable(BaseIterable):
 205    """
 206    Iterable returned by QuerySet.values_list(flat=False) that yields a tuple
 207    for each row.
 208    """
 209
 210    def __iter__(self) -> Iterator[tuple[Any, ...]]:
 211        queryset = self.queryset
 212        query = queryset.sql_query
 213        compiler = query.get_compiler()
 214
 215        if queryset._fields:
 216            names = [
 217                *query.values_select,
 218                *query.annotation_select,
 219            ]
 220            fields = [
 221                *queryset._fields,
 222                *(f for f in query.annotation_select if f not in queryset._fields),
 223            ]
 224            if fields != names:
 225                # Reorder according to fields.
 226                index_map = {name: idx for idx, name in enumerate(names)}
 227                rowfactory = operator.itemgetter(*[index_map[f] for f in fields])
 228                return map(
 229                    rowfactory,
 230                    compiler.results_iter(chunked_fetch=self.chunked_fetch),
 231                )
 232        return iter(
 233            compiler.results_iter(
 234                tuple_expected=True,
 235                chunked_fetch=self.chunked_fetch,
 236            )
 237        )
 238
 239
 240class FlatValuesListIterable(BaseIterable):
 241    """
 242    Iterable returned by QuerySet.values_list(flat=True) that yields single
 243    values.
 244    """
 245
 246    def __iter__(self) -> Iterator[Any]:
 247        queryset = self.queryset
 248        compiler = queryset.sql_query.get_compiler()
 249        for row in compiler.results_iter(chunked_fetch=self.chunked_fetch):
 250            yield row[0]
 251
 252
 253class QuerySet[T: "Model"]:
 254    """
 255    Represent a lazy database lookup for a set of objects.
 256
 257    Usage:
 258        MyModel.query.filter(name="test").all()
 259
 260    Custom QuerySets:
 261        from typing import Self
 262
 263        class TaskQuerySet(QuerySet["Task"]):
 264            def active(self) -> Self:
 265                return self.filter(is_active=True)
 266
 267        class Task(Model):
 268            is_active = BooleanField(default=True)
 269            query = TaskQuerySet()
 270
 271        Task.query.active().filter(name="test")  # Full type inference
 272
 273    Custom methods should return `Self` to preserve type through method chaining.
 274    """
 275
 276    # Instance attributes (set in from_model())
 277    model: type[T]
 278    _query: Query
 279    _result_cache: list[T] | None
 280    _sticky_filter: bool
 281    _prefetch_related_lookups: tuple[Any, ...]
 282    _prefetch_done: bool
 283    _known_related_objects: dict[Any, dict[Any, Any]]
 284    _iterable_class: type[BaseIterable]
 285    _fields: tuple[str, ...] | None
 286    _defer_next_filter: bool
 287    _deferred_filter: tuple[bool, tuple[Any, ...], dict[str, Any]] | None
 288
 289    def __init__(self):
 290        """Minimal init for descriptor mode. Use from_model() to create instances."""
 291
 292    @classmethod
 293    def from_model(cls, model: type[T], query: Query | None = None) -> Self:
 294        """Create a QuerySet instance bound to a model."""
 295        instance = cls()
 296        instance.model = model
 297        instance._query = query or Query(model)
 298        instance._result_cache = None
 299        instance._sticky_filter = False
 300        instance._prefetch_related_lookups = ()
 301        instance._prefetch_done = False
 302        instance._known_related_objects = {}
 303        instance._iterable_class = ModelIterable
 304        instance._fields = None
 305        instance._defer_next_filter = False
 306        instance._deferred_filter = None
 307        return instance
 308
 309    @overload
 310    def __get__(self, instance: None, owner: type[T]) -> Self: ...
 311
 312    @overload
 313    def __get__(self, instance: Model, owner: type[T]) -> Never: ...
 314
 315    def __get__(self, instance: Any, owner: type[T]) -> Self:
 316        """Descriptor protocol - return a new QuerySet bound to the model."""
 317        if instance is not None:
 318            raise AttributeError(
 319                f"QuerySet is only accessible from the model class, not instances. "
 320                f"Use {owner.__name__}.query instead."
 321            )
 322        return self.from_model(owner)
 323
 324    @property
 325    def sql_query(self) -> Query:
 326        if self._deferred_filter:
 327            negate, args, kwargs = self._deferred_filter
 328            self._filter_or_exclude_inplace(negate, args, kwargs)
 329            self._deferred_filter = None
 330        return self._query
 331
 332    @sql_query.setter
 333    def sql_query(self, value: Query) -> None:
 334        if value.values_select:
 335            self._iterable_class = ValuesIterable
 336        self._query = value
 337
 338    ########################
 339    # PYTHON MAGIC METHODS #
 340    ########################
 341
 342    def __deepcopy__(self, memo: dict[int, Any]) -> QuerySet[T]:
 343        """Don't populate the QuerySet's cache."""
 344        obj = self.__class__.from_model(self.model)
 345        for k, v in self.__dict__.items():
 346            if k == "_result_cache":
 347                obj.__dict__[k] = None
 348            else:
 349                obj.__dict__[k] = copy.deepcopy(v, memo)
 350        return obj
 351
 352    def __getstate__(self) -> dict[str, Any]:
 353        # Force the cache to be fully populated.
 354        self._fetch_all()
 355        return {**self.__dict__, PLAIN_VERSION_PICKLE_KEY: plain.runtime.__version__}
 356
 357    def __setstate__(self, state: dict[str, Any]) -> None:
 358        pickled_version = state.get(PLAIN_VERSION_PICKLE_KEY)
 359        if pickled_version:
 360            if pickled_version != plain.runtime.__version__:
 361                warnings.warn(
 362                    f"Pickled queryset instance's Plain version {pickled_version} does not "
 363                    f"match the current version {plain.runtime.__version__}.",
 364                    RuntimeWarning,
 365                    stacklevel=2,
 366                )
 367        else:
 368            warnings.warn(
 369                "Pickled queryset instance's Plain version is not specified.",
 370                RuntimeWarning,
 371                stacklevel=2,
 372            )
 373        self.__dict__.update(state)
 374
 375    def __repr__(self) -> str:
 376        # Don't run SQL from __repr__ — error reporters (Sentry, pdb,
 377        # exception templates) call repr() on stack-frame locals to
 378        # build error events. If the queryset hasn't been evaluated, a
 379        # surprise SELECT inside an exception path is a known footgun.
 380        if self._result_cache is None:
 381            return f"<{self.__class__.__name__} [unevaluated]>"
 382        data: list[Any] = list(self._result_cache[: REPR_OUTPUT_SIZE + 1])
 383        if len(data) > REPR_OUTPUT_SIZE:
 384            data[-1] = "...(remaining elements truncated)..."
 385        return f"<{self.__class__.__name__} {data!r}>"
 386
 387    def __len__(self) -> int:
 388        self._fetch_all()
 389        assert self._result_cache is not None
 390        return len(self._result_cache)
 391
 392    def __iter__(self) -> Iterator[T]:
 393        """
 394        The queryset iterator protocol uses three nested iterators in the
 395        default case:
 396            1. sql.compiler.execute_sql()
 397               - Returns a flat iterable of rows: a list from fetchall()
 398                 for regular queries, or a streaming generator from
 399                 cursor.stream() when using .iterator().
 400            2. sql.compiler.results_iter()
 401               - Returns one row at a time. At this point the rows are still
 402                 just tuples. In some cases the return values are converted
 403                 to Python values at this location.
 404            3. self.iterator()
 405               - Responsible for turning the rows into model objects.
 406        """
 407        self._fetch_all()
 408        assert self._result_cache is not None
 409        return iter(self._result_cache)
 410
 411    def __bool__(self) -> bool:
 412        self._fetch_all()
 413        return bool(self._result_cache)
 414
 415    @overload
 416    def __getitem__(self, k: int) -> T: ...
 417
 418    @overload
 419    def __getitem__(self, k: slice) -> QuerySet[T]: ...
 420
 421    def __getitem__(self, k: int | slice) -> T | QuerySet[T]:
 422        """Retrieve an item or slice from the set of results.
 423
 424        Slicing always returns a QuerySet, even when the results are
 425        already cached. The returned QuerySet behaves exactly like one
 426        sliced before evaluation — same allowed operations — except it
 427        carries the sliced cache so iterating it won't re-query. The slice
 428        is also applied as SQL limits, so any operation that re-chains the
 429        QuerySet drops the cache and re-queries the correct rows.
 430
 431        Negative indexing and step slicing both raise.
 432        """
 433        if not isinstance(k, int | slice):
 434            raise TypeError(
 435                f"QuerySet indices must be integers or slices, not {type(k).__name__}."
 436            )
 437
 438        if isinstance(k, slice):
 439            if (k.start is not None and k.start < 0) or (
 440                k.stop is not None and k.stop < 0
 441            ):
 442                raise ValueError("Negative indexing is not supported.")
 443            if k.step is not None:
 444                raise ValueError("Step slicing is not supported.")
 445            qs = self._chain()
 446            start = int(k.start) if k.start is not None else None
 447            stop = int(k.stop) if k.stop is not None else None
 448            qs.sql_query.set_limits(start, stop)
 449            if self._result_cache is not None:
 450                # Carry the sliced cache so the new QuerySet won't re-query on
 451                # iteration. The SQL limits above keep it correct if it's later
 452                # re-chained, which drops the cache.
 453                self._attach_result_cache(qs, self._result_cache[k])
 454            return qs
 455
 456        if k < 0:
 457            raise ValueError("Negative indexing is not supported.")
 458        if self._result_cache is not None:
 459            return self._result_cache[k]
 460
 461        qs = self._chain()
 462        qs.sql_query.set_limits(k, k + 1)
 463        qs._fetch_all()
 464        assert qs._result_cache is not None  # _fetch_all guarantees this
 465        return qs._result_cache[0]
 466
 467    def __class_getitem__(cls, *args: Any, **kwargs: Any) -> type[QuerySet[Any]]:
 468        return cls
 469
 470    def __and__(self, other: QuerySet[T]) -> QuerySet[T]:
 471        self._merge_sanity_check(other)
 472        if isinstance(other, EmptyQuerySet):
 473            return other
 474        if isinstance(self, EmptyQuerySet):
 475            return self
 476        combined = self._chain()
 477        combined._merge_known_related_objects(other)
 478        combined.sql_query.combine(other.sql_query, AND)
 479        return combined
 480
 481    def __or__(self, other: QuerySet[T]) -> QuerySet[T]:
 482        self._merge_sanity_check(other)
 483        if isinstance(self, EmptyQuerySet):
 484            return other
 485        if isinstance(other, EmptyQuerySet):
 486            return self
 487        query = (
 488            self
 489            if self.sql_query.can_filter()
 490            else self.model._model_meta.base_queryset.filter(id__in=self.values("id"))
 491        )
 492        combined = query._chain()
 493        combined._merge_known_related_objects(other)
 494        if not other.sql_query.can_filter():
 495            other = other.model._model_meta.base_queryset.filter(
 496                id__in=other.values("id")
 497            )
 498        combined.sql_query.combine(other.sql_query, OR)
 499        return combined
 500
 501    ####################################
 502    # METHODS THAT DO DATABASE QUERIES #
 503    ####################################
 504
 505    def _iterator(self, use_chunked_fetch: bool, chunk_size: int | None) -> Iterator[T]:
 506        iterable = self._iterable_class(
 507            self,
 508            chunked_fetch=use_chunked_fetch,
 509        )
 510        if not self._prefetch_related_lookups or chunk_size is None:
 511            yield from iterable
 512            return
 513
 514        iterator = iter(iterable)
 515        while results := list(islice(iterator, chunk_size)):
 516            prefetch_related_objects(results, *self._prefetch_related_lookups)
 517            yield from results
 518
 519    def iterator(self, chunk_size: int | None = None) -> Iterator[T]:
 520        """
 521        An iterator over the results from applying this QuerySet to the
 522        database. chunk_size must be provided for QuerySets that prefetch
 523        related objects. Otherwise, a default chunk_size of 2000 is supplied.
 524        """
 525        if chunk_size is None:
 526            if self._prefetch_related_lookups:
 527                raise ValueError(
 528                    "chunk_size must be provided when using QuerySet.iterator() after "
 529                    "prefetch_related()."
 530                )
 531        elif chunk_size <= 0:
 532            raise ValueError("Chunk size must be strictly positive.")
 533        # PostgreSQL always supports server-side cursors for chunked fetches
 534        return self._iterator(use_chunked_fetch=True, chunk_size=chunk_size)
 535
 536    def aggregate(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
 537        """
 538        Return a dictionary containing the calculations (aggregation)
 539        over the current queryset.
 540
 541        If args is present the expression is passed as a kwarg using
 542        the Aggregate object's default alias.
 543        """
 544        if self.sql_query.distinct_fields:
 545            raise NotImplementedError("aggregate() + distinct(fields) not implemented.")
 546        self._validate_values_are_expressions(
 547            (*args, *kwargs.values()), method_name="aggregate"
 548        )
 549        for arg in args:
 550            # The default_alias property raises TypeError if default_alias
 551            # can't be set automatically or AttributeError if it isn't an
 552            # attribute.
 553            try:
 554                arg.default_alias  # noqa: B018 — probe; raises for complex aggregates
 555            except (AttributeError, TypeError):
 556                raise TypeError("Complex aggregates require an alias")
 557            kwargs[arg.default_alias] = arg
 558
 559        return self.sql_query.chain().get_aggregation(kwargs)
 560
 561    def count(self) -> int:
 562        """
 563        Perform a SELECT COUNT() and return the number of records as an
 564        integer.
 565
 566        If the QuerySet is already fully cached, return the length of the
 567        cached results set to avoid multiple SELECT COUNT(*) calls.
 568        """
 569        if self._result_cache is not None:
 570            return len(self._result_cache)
 571
 572        return self.sql_query.get_count()
 573
 574    def get(self, *args: Any, **kwargs: Any) -> T:
 575        """
 576        Perform the query and return a single object matching the given
 577        keyword arguments.
 578        """
 579        clone = self.filter(*args, **kwargs)
 580        if self.sql_query.can_filter() and not self.sql_query.distinct_fields:
 581            clone = clone.order_by()
 582        limit = MAX_GET_RESULTS
 583        clone.sql_query.set_limits(high=limit)
 584        num = len(clone)
 585        if num == 1:
 586            assert clone._result_cache is not None  # len() fetches results
 587            return clone._result_cache[0]
 588        if not num:
 589            raise self.model.DoesNotExist(
 590                f"{self.model.model_options.object_name} matching query does not exist."
 591            )
 592        raise self.model.MultipleObjectsReturned(
 593            "get() returned more than one {} -- it returned {}!".format(
 594                self.model.model_options.object_name,
 595                num if not limit or num < limit else "more than %s" % (limit - 1),
 596            )
 597        )
 598
 599    def get_or_none(self, *args: Any, **kwargs: Any) -> T | None:
 600        """
 601        Perform the query and return a single object matching the given
 602        keyword arguments, or None if no object is found.
 603        """
 604        try:
 605            return self.get(*args, **kwargs)
 606        except self.model.DoesNotExist:
 607            return None
 608
 609    def create(self, **kwargs: Any) -> T:
 610        """
 611        Create a new object with the given kwargs, saving it to the database
 612        and returning the created object.
 613        """
 614        obj = self.model(**kwargs)
 615        obj.create()
 616        return obj
 617
 618    def _prepare_for_bulk_create(self, objs: list[T]) -> None:
 619        # The identity PK is the only PK type, so there's no literal Python
 620        # default to materialize -- obj.id stays None and the INSERT takes the
 621        # DB's DEFAULT path.
 622        for obj in objs:
 623            obj._prepare_related_fields_for_save(operation_name="bulk_create")
 624
 625    def _check_bulk_create_options(
 626        self,
 627        update_conflicts: bool,
 628        update_fields: list[Field] | None,
 629        unique_fields: list[Field] | None,
 630    ) -> OnConflict | None:
 631        if update_conflicts:
 632            if not update_fields:
 633                raise ValueError(
 634                    "Fields that will be updated when a row insertion fails "
 635                    "on conflicts must be provided."
 636                )
 637            if not unique_fields:
 638                raise ValueError(
 639                    "Unique fields that can trigger the upsert must be provided."
 640                )
 641            # Updating primary keys and many-to-many fields is forbidden.
 642            from plain.postgres.fields.related import ManyToManyField
 643
 644            if any(isinstance(f, ManyToManyField) for f in update_fields):
 645                raise ValueError(
 646                    "bulk_create() cannot be used with many-to-many fields in "
 647                    "update_fields."
 648                )
 649            if any(f.primary_key for f in update_fields):
 650                raise ValueError(
 651                    "bulk_create() cannot be used with primary keys in update_fields."
 652                )
 653            if unique_fields:
 654                from plain.postgres.fields.related import ManyToManyField
 655
 656                if any(isinstance(f, ManyToManyField) for f in unique_fields):
 657                    raise ValueError(
 658                        "bulk_create() cannot be used with many-to-many fields "
 659                        "in unique_fields."
 660                    )
 661            return OnConflict.UPDATE
 662        return None
 663
 664    def bulk_create(
 665        self,
 666        objs: Sequence[T],
 667        batch_size: int | None = None,
 668        update_conflicts: bool = False,
 669        update_fields: list[str] | None = None,
 670        unique_fields: list[str] | None = None,
 671    ) -> list[T]:
 672        """
 673        Insert each of the instances into the database. Do *not* call
 674        save() on each of the instances. Primary keys are set on the objects
 675        via the PostgreSQL RETURNING clause. Multi-table models are not supported.
 676        """
 677        if batch_size is not None and batch_size <= 0:
 678            raise ValueError("Batch size must be a positive integer.")
 679
 680        objs = list(objs)
 681        if not objs:
 682            return objs
 683        meta = self.model._model_meta
 684        unique_fields_objs: list[Field] | None = None
 685        update_fields_objs: list[Field] | None = None
 686        if unique_fields:
 687            unique_fields_objs = [
 688                meta.get_forward_field(name) for name in unique_fields
 689            ]
 690        if update_fields:
 691            update_fields_objs = [
 692                meta.get_forward_field(name) for name in update_fields
 693            ]
 694        on_conflict = self._check_bulk_create_options(
 695            update_conflicts,
 696            update_fields_objs,
 697            unique_fields_objs,
 698        )
 699        fields = meta.fields
 700        self._prepare_for_bulk_create(objs)
 701        with transaction.atomic(savepoint=False):
 702            objs_with_id, objs_without_id = partition(lambda o: o.id is None, objs)
 703            if objs_with_id:
 704                returned_columns = self._batched_insert(
 705                    objs_with_id,
 706                    fields,
 707                    batch_size,
 708                    on_conflict=on_conflict,
 709                    update_fields=update_fields_objs,
 710                    unique_fields=unique_fields_objs,
 711                )
 712                id_field = meta.get_forward_field("id")
 713                for obj_with_id, results in zip(objs_with_id, returned_columns):
 714                    for result, field in zip(results, meta.db_returning_fields):
 715                        if field != id_field:
 716                            setattr(obj_with_id, field.name, result)
 717                for obj_with_id in objs_with_id:
 718                    obj_with_id._state.adding = False
 719            if objs_without_id:
 720                fields = [f for f in fields if not isinstance(f, PrimaryKeyField)]
 721                returned_columns = self._batched_insert(
 722                    objs_without_id,
 723                    fields,
 724                    batch_size,
 725                    on_conflict=on_conflict,
 726                    update_fields=update_fields_objs,
 727                    unique_fields=unique_fields_objs,
 728                )
 729                if on_conflict is None:
 730                    assert len(returned_columns) == len(objs_without_id)
 731                for obj_without_id, results in zip(objs_without_id, returned_columns):
 732                    for result, field in zip(results, meta.db_returning_fields):
 733                        setattr(obj_without_id, field.name, result)
 734                    obj_without_id._state.adding = False
 735
 736        return objs
 737
 738    def bulk_update(
 739        self, objs: Sequence[T], fields: list[str], batch_size: int | None = None
 740    ) -> int:
 741        """
 742        Update the given fields in each of the given objects in the database.
 743        """
 744        if batch_size is not None and batch_size <= 0:
 745            raise ValueError("Batch size must be a positive integer.")
 746        if not fields:
 747            raise ValueError("Field names must be given to bulk_update().")
 748        objs_tuple = tuple(objs)
 749        if any(obj.id is None for obj in objs_tuple):
 750            raise ValueError("All bulk_update() objects must have a primary key set.")
 751        fields_list = [
 752            self.model._model_meta.get_forward_field(name) for name in fields
 753        ]
 754        from plain.postgres.fields.related import ManyToManyField
 755
 756        if any(isinstance(f, ManyToManyField) for f in fields_list):
 757            raise ValueError("bulk_update() cannot be used with many-to-many fields.")
 758        if any(f.primary_key for f in fields_list):
 759            raise ValueError("bulk_update() cannot be used with primary key fields.")
 760        if not objs_tuple:
 761            return 0
 762        for obj in objs_tuple:
 763            obj._prepare_related_fields_for_save(
 764                operation_name="bulk_update", field_names=fields
 765            )
 766        # PK is used twice in the resulting update query, once in the filter
 767        # and once in the WHEN. Each field will also have one CAST.
 768        max_batch_size = len(objs_tuple)
 769        batch_size = min(batch_size, max_batch_size) if batch_size else max_batch_size
 770        batches = (
 771            objs_tuple[i : i + batch_size]
 772            for i in range(0, len(objs_tuple), batch_size)
 773        )
 774        updates = []
 775        for batch_objs in batches:
 776            update_kwargs = {}
 777            for field in fields_list:
 778                when_statements = []
 779                for obj in batch_objs:
 780                    attr = field.value_from_object(obj)
 781                    if not isinstance(attr, ResolvableExpression):
 782                        attr = Value(attr, output_field=field)
 783                    when_statements.append(When(id=obj.id, then=attr))
 784                case_statement = Case(*when_statements, output_field=field)
 785                # PostgreSQL requires casted CASE in updates
 786                case_statement = Cast(case_statement, output_field=field)
 787                update_kwargs[field.name] = case_statement
 788            updates.append(([obj.id for obj in batch_objs], update_kwargs))
 789        rows_updated = 0
 790        queryset = self._chain()
 791        with transaction.atomic(savepoint=False):
 792            for ids, update_kwargs in updates:
 793                rows_updated += queryset.filter(id__in=ids).update(**update_kwargs)
 794        return rows_updated
 795
 796    def get_or_create(
 797        self, defaults: dict[str, Any] | None = None, **kwargs: Any
 798    ) -> tuple[T, bool]:
 799        """
 800        Look up an object with the given kwargs, creating one if necessary.
 801        Return a tuple of (object, created), where created is a boolean
 802        specifying whether an object was created.
 803        """
 804        # The get() needs to be targeted at the write database in order
 805        # to avoid potential transaction consistency problems.
 806        try:
 807            return self.get(**kwargs), False
 808        except self.model.DoesNotExist:
 809            params = self._extract_model_params(defaults, **kwargs)
 810            # Try to create an object using passed params.
 811            try:
 812                with transaction.atomic():
 813                    params = dict(resolve_callables(params))
 814                    return self.create(**params), True
 815            except (psycopg.IntegrityError, ValidationError):
 816                # Since create() also validates by default,
 817                # we can get any kind of ValidationError here,
 818                # or it can flow through and get an IntegrityError from the database.
 819                # The main thing we're concerned about is uniqueness failures,
 820                # but ValidationError could include other things too.
 821                # In all cases though it should be fine to try the get() again
 822                # and return an existing object.
 823                try:
 824                    return self.get(**kwargs), False
 825                except self.model.DoesNotExist:
 826                    pass
 827                raise
 828
 829    def update_or_create(
 830        self,
 831        defaults: dict[str, Any] | None = None,
 832        create_defaults: dict[str, Any] | None = None,
 833        **kwargs: Any,
 834    ) -> tuple[T, bool]:
 835        """
 836        Look up an object with the given kwargs, updating one with defaults
 837        if it exists, otherwise create a new one. Optionally, an object can
 838        be created with different values than defaults by using
 839        create_defaults.
 840        Return a tuple (object, created), where created is a boolean
 841        specifying whether an object was created.
 842        """
 843        if create_defaults is None:
 844            update_defaults = create_defaults = defaults or {}
 845        else:
 846            update_defaults = defaults or {}
 847        with transaction.atomic():
 848            # Lock the row so that a concurrent update is blocked until
 849            # update_or_create() has performed its save.
 850            obj, created = self.select_for_update().get_or_create(
 851                create_defaults, **kwargs
 852            )
 853            if created:
 854                return obj, created
 855            for k, v in resolve_callables(update_defaults):
 856                setattr(obj, k, v)
 857
 858            update_fields = set(update_defaults)
 859            field_names = self.model._model_meta._non_pk_field_names
 860            # update_fields only supports column-backed fields.
 861            if field_names.issuperset(update_fields):
 862                # Add fields which are set on pre_save(), e.g. update_now fields.
 863                # This is to maintain backward compatibility as these fields
 864                # are not updated unless explicitly specified in the
 865                # update_fields list.
 866                for field in self.model._model_meta.fields:
 867                    if not (
 868                        field.primary_key or field.__class__.pre_save is Field.pre_save
 869                    ):
 870                        update_fields.add(field.name)
 871                obj.update(fields=update_fields)
 872            else:
 873                obj.update()
 874        return obj, False
 875
 876    def _extract_model_params(
 877        self, defaults: dict[str, Any] | None, **kwargs: Any
 878    ) -> dict[str, Any]:
 879        """
 880        Prepare `params` for creating a model instance based on the given
 881        kwargs; for use by get_or_create().
 882        """
 883        defaults = defaults or {}
 884        params = {k: v for k, v in kwargs.items() if LOOKUP_SEP not in k}
 885        params.update(defaults)
 886        property_names = self.model._model_meta._property_names
 887        invalid_params = []
 888        for param in params:
 889            try:
 890                self.model._model_meta.get_field(param)
 891            except FieldDoesNotExist:
 892                # It's okay to use a model's property if it has a setter.
 893                if not (param in property_names and getattr(self.model, param).fset):
 894                    invalid_params.append(param)
 895        if invalid_params:
 896            raise FieldError(
 897                "Invalid field name(s) for model {}: '{}'.".format(
 898                    self.model.model_options.object_name,
 899                    "', '".join(sorted(invalid_params)),
 900                )
 901            )
 902        return params
 903
 904    def first(self) -> T | None:
 905        """Return the first object of a query or None if no match is found."""
 906        for obj in self[:1]:
 907            return obj
 908        return None
 909
 910    def last(self) -> T | None:
 911        """Return the last object of a query or None if no match is found."""
 912        queryset = self.reverse()
 913        for obj in queryset[:1]:
 914            return obj
 915        return None
 916
 917    def delete(self) -> int:
 918        """Delete the records in the current QuerySet.
 919
 920        Returns the number of parent rows deleted. Cascaded child rows are
 921        handled by Postgres via the declared `on_delete` clauses and are not
 922        included in the count.
 923        """
 924        if self.sql_query.is_sliced:
 925            raise TypeError("Cannot use 'limit' or 'offset' with delete().")
 926        if self.sql_query.distinct or self.sql_query.distinct_fields:
 927            raise TypeError("Cannot call delete() after .distinct().")
 928        if self._fields is not None:
 929            raise TypeError("Cannot call delete() after .values() or .values_list()")
 930
 931        del_query = self._chain()
 932        del_query.sql_query.select_for_update = False
 933        del_query.sql_query.select_related = False
 934        del_query.sql_query.clear_ordering(force=True)
 935
 936        # RESTRICT violations leave the DB transaction aborted. Mark the
 937        # connection so outer atomic() blocks see the abort state even if the
 938        # caller catches IntegrityError themselves.
 939        with transaction.mark_for_rollback_on_error():
 940            count = del_query._raw_delete()
 941
 942        # Clear the result cache, in case this QuerySet gets reused.
 943        self._result_cache = None
 944        return count
 945
 946    def _raw_delete(self) -> int:
 947        """
 948        Delete objects found from the given queryset in single direct SQL
 949        query. No signals are sent and there is no protection for cascades.
 950        """
 951        query = self.sql_query.clone()
 952        query.__class__ = DeleteQuery
 953        cursor = query.get_compiler().execute_sql(CURSOR)
 954        if cursor:
 955            with cursor:
 956                return cursor.rowcount
 957        return 0
 958
 959    def update(self, **kwargs: Any) -> int:
 960        """
 961        Update all elements in the current QuerySet, setting all the given
 962        fields to the appropriate values.
 963        """
 964        if self.sql_query.is_sliced:
 965            raise TypeError("Cannot update a query once a slice has been taken.")
 966        query = self.sql_query.chain(UpdateQuery)
 967        query.add_update_values(kwargs)
 968
 969        # Inline annotations in order_by(), if possible.
 970        new_order_by = []
 971        for col in query.order_by:
 972            alias = col
 973            descending = False
 974            if isinstance(alias, str) and alias.startswith("-"):
 975                alias = alias.removeprefix("-")
 976                descending = True
 977            if annotation := query.annotations.get(alias):
 978                if getattr(annotation, "contains_aggregate", False):
 979                    raise FieldError(
 980                        f"Cannot update when ordering by an aggregate: {annotation}"
 981                    )
 982                if descending:
 983                    annotation = annotation.desc()
 984                new_order_by.append(annotation)
 985            else:
 986                new_order_by.append(col)
 987        query.order_by = tuple(new_order_by)
 988
 989        # Clear any annotations so that they won't be present in subqueries.
 990        query.annotations = {}
 991        with transaction.mark_for_rollback_on_error():
 992            rows = query.get_compiler().execute_sql(CURSOR)
 993        self._result_cache = None
 994        return rows
 995
 996    def _update(self, values: Sequence[tuple[Field, Any]]) -> int:
 997        """
 998        A version of update() that accepts field objects instead of field names.
 999        Used primarily for model saving and not intended for use by general
1000        code (it requires too much poking around at model internals to be
1001        useful at that level).
1002        """
1003        if self.sql_query.is_sliced:
1004            raise TypeError("Cannot update a query once a slice has been taken.")
1005        query = self.sql_query.chain(UpdateQuery)
1006        query.add_update_fields(values)
1007        # Clear any annotations so that they won't be present in subqueries.
1008        query.annotations = {}
1009        self._result_cache = None
1010        return query.get_compiler().execute_sql(CURSOR)
1011
1012    def exists(self) -> bool:
1013        """
1014        Return True if the QuerySet would have any results, False otherwise.
1015        """
1016        if self._result_cache is None:
1017            return self.sql_query.has_results()
1018        return bool(self._result_cache)
1019
1020    def _prefetch_related_objects(self) -> None:
1021        # This method can only be called once the result cache has been filled.
1022        assert self._result_cache is not None
1023        prefetch_related_objects(self._result_cache, *self._prefetch_related_lookups)
1024        self._prefetch_done = True
1025
1026    def explain(self, *, format: str | None = None, **options: Any) -> str:
1027        """
1028        Runs an EXPLAIN on the SQL query this QuerySet would perform, and
1029        returns the results.
1030        """
1031        return self.sql_query.explain(format=format, **options)
1032
1033    ##################################################
1034    # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
1035    ##################################################
1036
1037    def raw(
1038        self,
1039        raw_query: str,
1040        params: Sequence[Any] = (),
1041        translations: dict[str, str] | None = None,
1042    ) -> RawQuerySet:
1043        qs = RawQuerySet(
1044            raw_query,
1045            model=self.model,
1046            params=tuple(params),
1047            translations=translations,
1048        )
1049        qs._prefetch_related_lookups = self._prefetch_related_lookups[:]
1050        return qs
1051
1052    def _values(self, *fields: str, **expressions: Any) -> QuerySet[Any]:
1053        clone = self._chain()
1054        if expressions:
1055            clone = clone.annotate(**expressions)
1056        clone._fields = fields
1057        clone.sql_query.set_values(list(fields))
1058        return clone
1059
1060    def values(self, *fields: str, **expressions: Any) -> QuerySet[Any]:
1061        fields += tuple(expressions)
1062        clone = self._values(*fields, **expressions)
1063        clone._iterable_class = ValuesIterable
1064        return clone
1065
1066    def values_list(self, *fields: str, flat: bool = False) -> QuerySet[Any]:
1067        if flat and len(fields) > 1:
1068            raise TypeError(
1069                "'flat' is not valid when values_list is called with more than one "
1070                "field."
1071            )
1072
1073        field_names = {f for f in fields if not isinstance(f, ResolvableExpression)}
1074        _fields = []
1075        expressions = {}
1076        counter = 1
1077        for field in fields:
1078            if isinstance(field, ResolvableExpression):
1079                field_id_prefix = getattr(
1080                    field, "default_alias", field.__class__.__name__.lower()
1081                )
1082                while True:
1083                    field_id = field_id_prefix + str(counter)
1084                    counter += 1
1085                    if field_id not in field_names:
1086                        break
1087                expressions[field_id] = field
1088                _fields.append(field_id)
1089            else:
1090                _fields.append(field)
1091
1092        clone = self._values(*_fields, **expressions)
1093        clone._iterable_class = FlatValuesListIterable if flat else ValuesListIterable
1094        return clone
1095
1096    def none(self) -> QuerySet[T]:
1097        """Return an empty QuerySet."""
1098        clone = self._chain()
1099        clone.sql_query.set_empty()
1100        return clone
1101
1102    ##################################################################
1103    # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
1104    ##################################################################
1105
1106    def all(self) -> Self:
1107        """
1108        Return a new QuerySet that is a copy of the current one. This allows a
1109        QuerySet to proxy for a model queryset in some cases.
1110        """
1111        obj = self._chain()
1112        # Preserve cache since all() doesn't modify the query.
1113        if self._result_cache is not None:
1114            self._attach_result_cache(obj, self._result_cache)
1115        return obj
1116
1117    def filter(self, *args: Any, **kwargs: Any) -> Self:
1118        """
1119        Return a new QuerySet instance with the args ANDed to the existing
1120        set.
1121        """
1122        return self._filter_or_exclude(False, args, kwargs)
1123
1124    def exclude(self, *args: Any, **kwargs: Any) -> Self:
1125        """
1126        Return a new QuerySet instance with NOT (args) ANDed to the existing
1127        set.
1128        """
1129        return self._filter_or_exclude(True, args, kwargs)
1130
1131    def _filter_or_exclude(
1132        self, negate: bool, args: tuple[Any, ...], kwargs: dict[str, Any]
1133    ) -> Self:
1134        if (args or kwargs) and self.sql_query.is_sliced:
1135            raise TypeError("Cannot filter a query once a slice has been taken.")
1136        clone = self._chain()
1137        if self._defer_next_filter:
1138            self._defer_next_filter = False
1139            clone._deferred_filter = negate, args, kwargs
1140        else:
1141            clone._filter_or_exclude_inplace(negate, args, kwargs)
1142        return clone
1143
1144    def _filter_or_exclude_inplace(
1145        self, negate: bool, args: tuple[Any, ...], kwargs: dict[str, Any]
1146    ) -> None:
1147        if negate:
1148            self._query.add_q(~Q(*args, **kwargs))
1149        else:
1150            self._query.add_q(Q(*args, **kwargs))
1151
1152    def select_for_update(
1153        self,
1154        nowait: bool = False,
1155        skip_locked: bool = False,
1156        of: tuple[str, ...] = (),
1157        no_key: bool = False,
1158    ) -> QuerySet[T]:
1159        """
1160        Return a new QuerySet instance that will select objects with a
1161        FOR UPDATE lock.
1162        """
1163        if nowait and skip_locked:
1164            raise ValueError("The nowait option cannot be used with skip_locked.")
1165        obj = self._chain()
1166        obj.sql_query.select_for_update = True
1167        obj.sql_query.select_for_update_nowait = nowait
1168        obj.sql_query.select_for_update_skip_locked = skip_locked
1169        obj.sql_query.select_for_update_of = of
1170        obj.sql_query.select_for_no_key_update = no_key
1171        return obj
1172
1173    def select_related(self, *fields: str | None) -> Self:
1174        """
1175        Return a new QuerySet instance that will select related objects.
1176
1177        If fields are specified, they must be ForeignKeyField fields and only those
1178        related objects are included in the selection.
1179
1180        If select_related(None) is called, clear the list.
1181        """
1182        if self._fields is not None:
1183            raise TypeError(
1184                "Cannot call select_related() after .values() or .values_list()"
1185            )
1186
1187        obj = self._chain()
1188        if fields == (None,):
1189            obj.sql_query.select_related = False
1190        elif fields:
1191            obj.sql_query.add_select_related(list(fields))  # ty: ignore[invalid-argument-type]
1192        else:
1193            obj.sql_query.select_related = True
1194        return obj
1195
1196    def prefetch_related(self, *lookups: str | Prefetch | None) -> Self:
1197        """
1198        Return a new QuerySet instance that will prefetch the specified
1199        Many-To-One and Many-To-Many related objects when the QuerySet is
1200        evaluated.
1201
1202        When prefetch_related() is called more than once, append to the list of
1203        prefetch lookups. If prefetch_related(None) is called, clear the list.
1204        """
1205        clone = self._chain()
1206        if lookups == (None,):
1207            clone._prefetch_related_lookups = ()
1208        else:
1209            clone._prefetch_related_lookups = clone._prefetch_related_lookups + lookups
1210        return clone
1211
1212    def annotate(self, *args: Any, **kwargs: Any) -> Self:
1213        """
1214        Return a query set in which the returned objects have been annotated
1215        with extra data or aggregations.
1216        """
1217        self._validate_values_are_expressions(
1218            args + tuple(kwargs.values()), method_name="annotate"
1219        )
1220        annotations = {}
1221        for arg in args:
1222            # The default_alias property may raise a TypeError.
1223            try:
1224                if arg.default_alias in kwargs:
1225                    raise ValueError(
1226                        f"The named annotation '{arg.default_alias}' conflicts with the "
1227                        "default name for another annotation."
1228                    )
1229            except TypeError:
1230                raise TypeError("Complex annotations require an alias")
1231            annotations[arg.default_alias] = arg
1232        annotations.update(kwargs)
1233
1234        clone = self._chain()
1235        names = self._fields
1236        if names is None:
1237            names = {field.name for field in self.model._model_meta.get_fields()}
1238
1239        for alias, annotation in annotations.items():
1240            if alias in names:
1241                raise ValueError(
1242                    f"The annotation '{alias}' conflicts with a field on the model."
1243                )
1244            clone.sql_query.add_annotation(annotation, alias)
1245        for alias, annotation in clone.sql_query.annotations.items():
1246            if alias in annotations and annotation.contains_aggregate:
1247                if clone._fields is None:
1248                    clone.sql_query.group_by = True
1249                else:
1250                    clone.sql_query.set_group_by()
1251                break
1252
1253        return clone
1254
1255    def order_by(self, *field_names: str | ResolvableExpression) -> Self:
1256        """Return a new QuerySet instance with the ordering changed."""
1257        if self.sql_query.is_sliced:
1258            raise TypeError("Cannot reorder a query once a slice has been taken.")
1259        obj = self._chain()
1260        obj.sql_query.clear_ordering(force=True, clear_default=False)
1261        obj.sql_query.add_ordering(*field_names)
1262        return obj
1263
1264    def distinct(self, *field_names: str) -> Self:
1265        """
1266        Return a new QuerySet instance that will select only distinct results.
1267        """
1268        if self.sql_query.is_sliced:
1269            raise TypeError(
1270                "Cannot create distinct fields once a slice has been taken."
1271            )
1272        obj = self._chain()
1273        obj.sql_query.add_distinct_fields(*field_names)
1274        return obj
1275
1276    def reverse(self) -> QuerySet[T]:
1277        """Reverse the ordering of the QuerySet."""
1278        if self.sql_query.is_sliced:
1279            raise TypeError("Cannot reverse a query once a slice has been taken.")
1280        clone = self._chain()
1281        clone.sql_query.standard_ordering = not clone.sql_query.standard_ordering
1282        return clone
1283
1284    def defer(self, *fields: str | None) -> QuerySet[T]:
1285        """
1286        Defer the loading of data for certain fields until they are accessed.
1287        Add the set of deferred fields to any existing set of deferred fields.
1288        The only exception to this is if None is passed in as the only
1289        parameter, in which case removal all deferrals.
1290        """
1291        if self._fields is not None:
1292            raise TypeError("Cannot call defer() after .values() or .values_list()")
1293        clone = self._chain()
1294        if fields == (None,):
1295            clone.sql_query.clear_deferred_loading()
1296        else:
1297            clone.sql_query.add_deferred_loading(frozenset(fields))  # ty: ignore[invalid-argument-type]
1298        return clone
1299
1300    def only(self, *fields: str) -> QuerySet[T]:
1301        """
1302        Essentially, the opposite of defer(). Only the fields passed into this
1303        method and that are not already specified as deferred are loaded
1304        immediately when the queryset is evaluated.
1305        """
1306        if self._fields is not None:
1307            raise TypeError("Cannot call only() after .values() or .values_list()")
1308        if fields == (None,):
1309            # Can only pass None to defer(), not only(), as the rest option.
1310            # That won't stop people trying to do this, so let's be explicit.
1311            raise TypeError("Cannot pass None as an argument to only().")
1312        clone = self._chain()
1313        clone.sql_query.add_immediate_loading(set(fields))
1314        return clone
1315
1316    ###################################
1317    # PUBLIC INTROSPECTION ATTRIBUTES #
1318    ###################################
1319
1320    @property
1321    def ordered(self) -> bool:
1322        """
1323        Return True if the QuerySet is ordered -- i.e. has an order_by()
1324        clause or a default ordering on the model (or is empty).
1325        """
1326        if isinstance(self, EmptyQuerySet):
1327            return True
1328        return bool(
1329            self.sql_query.order_by
1330            or (
1331                self.sql_query.default_ordering
1332                and self.sql_query.model
1333                and self.sql_query.model.model_options.ordering
1334                and
1335                # A default ordering doesn't affect GROUP BY queries.
1336                not self.sql_query.group_by
1337            )
1338        )
1339
1340    ###################
1341    # PRIVATE METHODS #
1342    ###################
1343
1344    def _insert(
1345        self,
1346        objs: list[T],
1347        fields: Sequence[Field],
1348        returning_fields: list[Field] | None = None,
1349        on_conflict: OnConflict | None = None,
1350        update_fields: list[Field] | None = None,
1351        unique_fields: list[Field] | None = None,
1352    ) -> list[tuple[Any, ...]] | None:
1353        """
1354        Insert a new record for the given model. This provides an interface to
1355        the InsertQuery class and is how Model.create() is implemented.
1356        """
1357        query = InsertQuery(
1358            self.model,
1359            on_conflict=on_conflict if on_conflict else None,
1360            update_fields=update_fields,
1361            unique_fields=unique_fields,
1362        )
1363        query.insert_values(fields, objs)
1364        # InsertQuery returns SQLInsertCompiler which has different execute_sql signature
1365        return query.get_compiler().execute_sql(returning_fields)
1366
1367    def _batched_insert(
1368        self,
1369        objs: list[T],
1370        fields: Sequence[Field],
1371        batch_size: int | None,
1372        on_conflict: OnConflict | None = None,
1373        update_fields: list[Field] | None = None,
1374        unique_fields: list[Field] | None = None,
1375    ) -> list[tuple[Any, ...]]:
1376        """
1377        Helper method for bulk_create() to insert objs one batch at a time.
1378        """
1379        max_batch_size = max(len(objs), 1)
1380        batch_size = min(batch_size, max_batch_size) if batch_size else max_batch_size
1381        inserted_rows = []
1382        for item in [objs[i : i + batch_size] for i in range(0, len(objs), batch_size)]:
1383            if on_conflict is None:
1384                inserted_rows.extend(
1385                    self._insert(  # ty: ignore[invalid-argument-type]
1386                        item,
1387                        fields=fields,
1388                        returning_fields=self.model._model_meta.db_returning_fields,
1389                    )
1390                )
1391            else:
1392                self._insert(
1393                    item,
1394                    fields=fields,
1395                    on_conflict=on_conflict,
1396                    update_fields=update_fields,
1397                    unique_fields=unique_fields,
1398                )
1399        return inserted_rows
1400
1401    def _chain(self) -> Self:
1402        """
1403        Return a copy of the current QuerySet that's ready for another
1404        operation.
1405        """
1406        obj = self._clone()
1407        if obj._sticky_filter:
1408            obj.sql_query.filter_is_sticky = True
1409            obj._sticky_filter = False
1410        return obj
1411
1412    def _clone(self) -> Self:
1413        """
1414        Return a copy of the current QuerySet. A lightweight alternative
1415        to deepcopy().
1416        """
1417        c = self.__class__.from_model(
1418            model=self.model,
1419            query=self.sql_query.chain(),
1420        )
1421        c._sticky_filter = self._sticky_filter
1422        c._prefetch_related_lookups = self._prefetch_related_lookups[:]
1423        c._known_related_objects = self._known_related_objects
1424        c._iterable_class = self._iterable_class
1425        c._fields = self._fields
1426        return c
1427
1428    def _attach_result_cache(self, obj: Self, cache: list[T]) -> None:
1429        """Carry a result cache onto a chained QuerySet.
1430
1431        Whenever a cache is moved onto a new QuerySet, the prefetch state
1432        must ride along with it — otherwise prefetch_related() would re-run
1433        (or be skipped). Keep both writes together here so callers can't
1434        forget the pairing.
1435        """
1436        obj._result_cache = cache
1437        obj._prefetch_done = self._prefetch_done
1438
1439    def _fetch_all(self) -> None:
1440        if self._result_cache is None:
1441            self._result_cache = list(self._iterable_class(self))
1442        if self._prefetch_related_lookups and not self._prefetch_done:
1443            self._prefetch_related_objects()
1444
1445    def _next_is_sticky(self) -> QuerySet[T]:
1446        """
1447        Indicate that the next filter call and the one following that should
1448        be treated as a single filter. This is only important when it comes to
1449        determining when to reuse tables for many-to-many filters. Required so
1450        that we can filter naturally on the results of related managers.
1451
1452        This doesn't return a clone of the current QuerySet (it returns
1453        "self"). The method is only used internally and should be immediately
1454        followed by a filter() that does create a clone.
1455        """
1456        self._sticky_filter = True
1457        return self
1458
1459    def _merge_sanity_check(self, other: QuerySet[T]) -> None:
1460        """Check that two QuerySet classes may be merged."""
1461        if self._fields is not None and (
1462            set(self.sql_query.values_select) != set(other.sql_query.values_select)
1463            or set(self.sql_query.annotation_select)
1464            != set(other.sql_query.annotation_select)
1465        ):
1466            raise TypeError(
1467                f"Merging '{self.__class__.__name__}' classes must involve the same values in each case."
1468            )
1469
1470    def _merge_known_related_objects(self, other: QuerySet[T]) -> None:
1471        """
1472        Keep track of all known related objects from either QuerySet instance.
1473        """
1474        for field, objects in other._known_related_objects.items():
1475            self._known_related_objects.setdefault(field, {}).update(objects)
1476
1477    def resolve_expression(self, *args: Any, **kwargs: Any) -> Query:
1478        if self._fields and len(self._fields) > 1:
1479            # values() queryset can only be used as nested queries
1480            # if they are set up to select only a single field.
1481            raise TypeError("Cannot use multi-field values as a filter value.")
1482        query = self.sql_query.resolve_expression(*args, **kwargs)
1483        return query
1484
1485    def _has_filters(self) -> bool:
1486        """
1487        Check if this QuerySet has any filtering going on. This isn't
1488        equivalent with checking if all objects are present in results, for
1489        example, qs[1:]._has_filters() -> False.
1490        """
1491        return self.sql_query.has_filters()
1492
1493    @staticmethod
1494    def _validate_values_are_expressions(
1495        values: tuple[Any, ...], method_name: str
1496    ) -> None:
1497        invalid_args = sorted(
1498            str(arg) for arg in values if not isinstance(arg, ResolvableExpression)
1499        )
1500        if invalid_args:
1501            raise TypeError(
1502                "QuerySet.{}() received non-expression(s): {}.".format(
1503                    method_name,
1504                    ", ".join(invalid_args),
1505                )
1506            )
1507
1508
1509class InstanceCheckMeta(type):
1510    def __instancecheck__(self, instance: object) -> bool:
1511        return isinstance(instance, QuerySet) and instance.sql_query.is_empty()
1512
1513
1514class EmptyQuerySet(metaclass=InstanceCheckMeta):
1515    """
1516    Marker class to checking if a queryset is empty by .none():
1517        isinstance(qs.none(), EmptyQuerySet) -> True
1518    """
1519
1520    def __init__(self, *args: Any, **kwargs: Any):
1521        raise TypeError("EmptyQuerySet can't be instantiated")
1522
1523
1524class RawQuerySet:
1525    """
1526    Provide an iterator which converts the results of raw SQL queries into
1527    annotated model instances.
1528    """
1529
1530    def __init__(
1531        self,
1532        raw_query: str,
1533        model: type[Model] | None = None,
1534        query: RawQuery | None = None,
1535        params: tuple[Any, ...] = (),
1536        translations: dict[str, str] | None = None,
1537    ):
1538        self.raw_query = raw_query
1539        self.model = model
1540        self.sql_query = query or RawQuery(sql=raw_query, params=params)
1541        self.params = params
1542        self.translations = translations or {}
1543        self._result_cache: list[Model] | None = None
1544        self._prefetch_related_lookups: tuple[Any, ...] = ()
1545        self._prefetch_done = False
1546
1547    def resolve_model_init_order(
1548        self,
1549    ) -> tuple[list[str], list[int], list[tuple[str, int]]]:
1550        """Resolve the init field names and value positions."""
1551        model = self.model
1552        assert model is not None
1553        model_init_fields = [
1554            f for f in model._model_meta.fields if f.column in self.columns
1555        ]
1556        annotation_fields = [
1557            (column, pos)
1558            for pos, column in enumerate(self.columns)
1559            if column not in self.model_fields
1560        ]
1561        model_init_order = [self.columns.index(f.column) for f in model_init_fields]
1562        model_init_names = [f.name for f in model_init_fields]
1563        return model_init_names, model_init_order, annotation_fields
1564
1565    def prefetch_related(self, *lookups: str | Prefetch | None) -> RawQuerySet:
1566        """Same as QuerySet.prefetch_related()"""
1567        clone = self._clone()
1568        if lookups == (None,):
1569            clone._prefetch_related_lookups = ()
1570        else:
1571            clone._prefetch_related_lookups = clone._prefetch_related_lookups + lookups
1572        return clone
1573
1574    def _prefetch_related_objects(self) -> None:
1575        assert self._result_cache is not None
1576        prefetch_related_objects(self._result_cache, *self._prefetch_related_lookups)
1577        self._prefetch_done = True
1578
1579    def _clone(self) -> RawQuerySet:
1580        """Same as QuerySet._clone()"""
1581        c = self.__class__(
1582            self.raw_query,
1583            model=self.model,
1584            query=self.sql_query,
1585            params=self.params,
1586            translations=self.translations,
1587        )
1588        c._prefetch_related_lookups = self._prefetch_related_lookups[:]
1589        return c
1590
1591    def _fetch_all(self) -> None:
1592        if self._result_cache is None:
1593            self._result_cache = list(self.iterator())
1594        if self._prefetch_related_lookups and not self._prefetch_done:
1595            self._prefetch_related_objects()
1596
1597    def __len__(self) -> int:
1598        self._fetch_all()
1599        assert self._result_cache is not None
1600        return len(self._result_cache)
1601
1602    def __bool__(self) -> bool:
1603        self._fetch_all()
1604        return bool(self._result_cache)
1605
1606    def __iter__(self) -> Iterator[Model]:
1607        self._fetch_all()
1608        assert self._result_cache is not None
1609        return iter(self._result_cache)
1610
1611    def iterator(self) -> Iterator[Model]:
1612        yield from RawModelIterable(self)  # ty: ignore[invalid-argument-type]
1613
1614    def __repr__(self) -> str:
1615        return f"<{self.__class__.__name__}: {self.sql_query}>"
1616
1617    def __getitem__(self, k: int | slice) -> Model | list[Model]:
1618        # Unlike QuerySet, a RawQuerySet is always fully materialized — there's
1619        # no lazy query to push a slice into — so indexing keeps plain list
1620        # semantics: a slice returns a list (and step/negative slicing work).
1621        return list(self)[k]
1622
1623    @cached_property
1624    def columns(self) -> list[str]:
1625        """
1626        A list of model field names in the order they'll appear in the
1627        query results.
1628        """
1629        columns = self.sql_query.get_columns()
1630        # Adjust any column names which don't match field names
1631        for query_name, model_name in self.translations.items():
1632            # Ignore translations for nonexistent column names
1633            try:
1634                index = columns.index(query_name)
1635            except ValueError:
1636                pass
1637            else:
1638                columns[index] = model_name
1639        return columns
1640
1641    @cached_property
1642    def model_fields(self) -> dict[str, Field]:
1643        """A dict mapping column names to model field names."""
1644        model_fields = {}
1645        model = self.model
1646        assert model is not None
1647        for field in model._model_meta.fields:
1648            model_fields[field.column] = field
1649        return model_fields
1650
1651
1652class Prefetch:
1653    def __init__(
1654        self,
1655        lookup: str,
1656        queryset: QuerySet[Any] | None = None,
1657        to_attr: str | None = None,
1658    ):
1659        # `prefetch_through` is the path we traverse to perform the prefetch.
1660        self.prefetch_through = lookup
1661        # `prefetch_to` is the path to the attribute that stores the result.
1662        self.prefetch_to = lookup
1663        if queryset is not None and (
1664            isinstance(queryset, RawQuerySet)
1665            or (
1666                hasattr(queryset, "_iterable_class")
1667                and not issubclass(queryset._iterable_class, ModelIterable)
1668            )
1669        ):
1670            raise ValueError(
1671                "Prefetch querysets cannot use raw(), values(), and values_list()."
1672            )
1673        if to_attr:
1674            self.prefetch_to = LOOKUP_SEP.join(
1675                lookup.split(LOOKUP_SEP)[:-1] + [to_attr]
1676            )
1677
1678        self.queryset = queryset
1679        self.to_attr = to_attr
1680
1681    def __getstate__(self) -> dict[str, Any]:
1682        obj_dict = self.__dict__.copy()
1683        if self.queryset is not None:
1684            queryset = self.queryset._chain()
1685            # Prevent the QuerySet from being evaluated
1686            queryset._result_cache = []
1687            queryset._prefetch_done = True
1688            obj_dict["queryset"] = queryset
1689        return obj_dict
1690
1691    def add_prefix(self, prefix: str) -> None:
1692        self.prefetch_through = prefix + LOOKUP_SEP + self.prefetch_through
1693        self.prefetch_to = prefix + LOOKUP_SEP + self.prefetch_to
1694
1695    def get_current_prefetch_to(self, level: int) -> str:
1696        return LOOKUP_SEP.join(self.prefetch_to.split(LOOKUP_SEP)[: level + 1])
1697
1698    def get_current_to_attr(self, level: int) -> tuple[str, bool]:
1699        parts = self.prefetch_to.split(LOOKUP_SEP)
1700        to_attr = parts[level]
1701        as_attr = bool(self.to_attr and level == len(parts) - 1)
1702        return to_attr, as_attr
1703
1704    def get_current_queryset(self, level: int) -> QuerySet[Any] | None:
1705        if self.get_current_prefetch_to(level) == self.prefetch_to:
1706            return self.queryset
1707        return None
1708
1709    def __eq__(self, other: object) -> bool:
1710        if not isinstance(other, Prefetch):
1711            return NotImplemented
1712        return self.prefetch_to == other.prefetch_to
1713
1714    def __hash__(self) -> int:
1715        return hash((self.__class__, self.prefetch_to))
1716
1717
1718def normalize_prefetch_lookups(
1719    lookups: tuple[str | Prefetch, ...] | list[str | Prefetch],
1720    prefix: str | None = None,
1721) -> list[Prefetch]:
1722    """Normalize lookups into Prefetch objects."""
1723    ret = []
1724    for lookup in lookups:
1725        if not isinstance(lookup, Prefetch):
1726            lookup = Prefetch(lookup)
1727        if prefix:
1728            lookup.add_prefix(prefix)
1729        ret.append(lookup)
1730    return ret
1731
1732
1733def prefetch_related_objects(
1734    model_instances: Sequence[Model], *related_lookups: str | Prefetch
1735) -> None:
1736    """
1737    Populate prefetched object caches for a list of model instances based on
1738    the lookups/Prefetch instances given.
1739    """
1740    if not model_instances:
1741        return  # nothing to do
1742
1743    # We need to be able to dynamically add to the list of prefetch_related
1744    # lookups that we look up (see below).  So we need some book keeping to
1745    # ensure we don't do duplicate work.
1746    done_queries = {}  # dictionary of things like 'foo__bar': [results]
1747
1748    auto_lookups = set()  # we add to this as we go through.
1749    followed_descriptors = set()  # recursion protection
1750
1751    all_lookups = normalize_prefetch_lookups(list(reversed(related_lookups)))
1752    while all_lookups:
1753        lookup = all_lookups.pop()
1754        if lookup.prefetch_to in done_queries:
1755            if lookup.queryset is not None:
1756                raise ValueError(
1757                    f"'{lookup.prefetch_to}' lookup was already seen with a different queryset. "
1758                    "You may need to adjust the ordering of your lookups."
1759                )
1760
1761            continue
1762
1763        # Top level, the list of objects to decorate is the result cache
1764        # from the primary QuerySet. It won't be for deeper levels.
1765        obj_list = model_instances
1766
1767        through_attrs = lookup.prefetch_through.split(LOOKUP_SEP)
1768        for level, through_attr in enumerate(through_attrs):
1769            # Prepare main instances
1770            if not obj_list:
1771                break
1772
1773            prefetch_to = lookup.get_current_prefetch_to(level)
1774            if prefetch_to in done_queries:
1775                # Skip any prefetching, and any object preparation
1776                obj_list = done_queries[prefetch_to]
1777                continue
1778
1779            # Prepare objects:
1780            good_objects = True
1781            for obj in obj_list:
1782                # Since prefetching can re-use instances, it is possible to have
1783                # the same instance multiple times in obj_list, so obj might
1784                # already be prepared.
1785                if not hasattr(obj, "_prefetched_objects_cache"):
1786                    try:
1787                        obj._prefetched_objects_cache = {}
1788                    except (AttributeError, TypeError):
1789                        # Must be an immutable object from
1790                        # values_list(flat=True), for example (TypeError) or
1791                        # a QuerySet subclass that isn't returning Model
1792                        # instances (AttributeError), either in Plain or a 3rd
1793                        # party. prefetch_related() doesn't make sense, so quit.
1794                        good_objects = False
1795                        break
1796            if not good_objects:
1797                break
1798
1799            # Descend down tree
1800
1801            # We assume that objects retrieved are homogeneous (which is the premise
1802            # of prefetch_related), so what applies to first object applies to all.
1803            first_obj = obj_list[0]
1804            to_attr = lookup.get_current_to_attr(level)[0]
1805            prefetcher, descriptor, attr_found, is_fetched = get_prefetcher(
1806                first_obj, through_attr, to_attr
1807            )
1808
1809            if not attr_found:
1810                raise AttributeError(
1811                    f"Cannot find '{through_attr}' on {first_obj.__class__.__name__} object, '{lookup.prefetch_through}' is an invalid "
1812                    "parameter to prefetch_related()"
1813                )
1814
1815            if level == len(through_attrs) - 1 and prefetcher is None:
1816                # Last one, this *must* resolve to something that supports
1817                # prefetching, otherwise there is no point adding it and the
1818                # developer asking for it has made a mistake.
1819                raise ValueError(
1820                    f"'{lookup.prefetch_through}' does not resolve to an item that supports "
1821                    "prefetching - this is an invalid parameter to "
1822                    "prefetch_related()."
1823                )
1824
1825            obj_to_fetch = None
1826            if prefetcher is not None:
1827                obj_to_fetch = [obj for obj in obj_list if not is_fetched(obj)]
1828
1829            if obj_to_fetch:
1830                obj_list, additional_lookups = prefetch_one_level(
1831                    obj_to_fetch,
1832                    prefetcher,
1833                    lookup,
1834                    level,
1835                )
1836                # We need to ensure we don't keep adding lookups from the
1837                # same relationships to stop infinite recursion. So, if we
1838                # are already on an automatically added lookup, don't add
1839                # the new lookups from relationships we've seen already.
1840                if not (
1841                    prefetch_to in done_queries
1842                    and lookup in auto_lookups
1843                    and descriptor in followed_descriptors
1844                ):
1845                    done_queries[prefetch_to] = obj_list
1846                    new_lookups = normalize_prefetch_lookups(
1847                        list(reversed(additional_lookups)),
1848                        prefetch_to,
1849                    )
1850                    auto_lookups.update(new_lookups)
1851                    all_lookups.extend(new_lookups)
1852                followed_descriptors.add(descriptor)
1853            else:
1854                # Either a singly related object that has already been fetched
1855                # (e.g. via select_related), or hopefully some other property
1856                # that doesn't support prefetching but needs to be traversed.
1857
1858                # We replace the current list of parent objects with the list
1859                # of related objects, filtering out empty or missing values so
1860                # that we can continue with nullable or reverse relations.
1861                new_obj_list = []
1862                for obj in obj_list:
1863                    if through_attr in getattr(obj, "_prefetched_objects_cache", ()):
1864                        # If related objects have been prefetched, use the
1865                        # cache rather than the object's through_attr.
1866                        new_obj = list(obj._prefetched_objects_cache.get(through_attr))  # ty: ignore[invalid-argument-type]
1867                    else:
1868                        try:
1869                            new_obj = getattr(obj, through_attr)
1870                        except ObjectDoesNotExist:
1871                            continue
1872                    if new_obj is None:
1873                        continue
1874                    # We special-case `list` rather than something more generic
1875                    # like `Iterable` because we don't want to accidentally match
1876                    # user models that define __iter__.
1877                    if isinstance(new_obj, list):
1878                        new_obj_list.extend(new_obj)
1879                    else:
1880                        new_obj_list.append(new_obj)
1881                obj_list = new_obj_list
1882
1883
1884def get_prefetcher(
1885    instance: Model, through_attr: str, to_attr: str
1886) -> tuple[Any, Any, bool, Callable[[Model], bool]]:
1887    """
1888    For the attribute 'through_attr' on the given instance, find
1889    an object that has a get_prefetch_queryset().
1890    Return a 4 tuple containing:
1891    (the object with get_prefetch_queryset (or None),
1892     the descriptor object representing this relationship (or None),
1893     a boolean that is False if the attribute was not found at all,
1894     a function that takes an instance and returns a boolean that is True if
1895     the attribute has already been fetched for that instance)
1896    """
1897
1898    def has_to_attr_attribute(instance: Model) -> bool:
1899        return hasattr(instance, to_attr)
1900
1901    prefetcher = None
1902    is_fetched: Callable[[Model], bool] = has_to_attr_attribute
1903
1904    # For singly related objects, we have to avoid getting the attribute
1905    # from the object, as this will trigger the query. So we first try
1906    # on the class, in order to get the descriptor object.
1907    rel_obj_descriptor = getattr(instance.__class__, through_attr, None)
1908    if rel_obj_descriptor is None:
1909        attr_found = hasattr(instance, through_attr)
1910    else:
1911        attr_found = True
1912        if rel_obj_descriptor:
1913            # singly related object, descriptor object has the
1914            # get_prefetch_queryset() method.
1915            if hasattr(rel_obj_descriptor, "get_prefetch_queryset"):
1916                prefetcher = rel_obj_descriptor
1917                is_fetched = rel_obj_descriptor.is_cached
1918            else:
1919                # descriptor doesn't support prefetching, so we go ahead and get
1920                # the attribute on the instance rather than the class to
1921                # support many related managers
1922                rel_obj = getattr(instance, through_attr)
1923                if hasattr(rel_obj, "get_prefetch_queryset"):
1924                    prefetcher = rel_obj
1925                if through_attr != to_attr:
1926                    # Special case cached_property instances because hasattr
1927                    # triggers attribute computation and assignment.
1928                    if isinstance(
1929                        getattr(instance.__class__, to_attr, None), cached_property
1930                    ):
1931
1932                        def has_cached_property(instance: Model) -> bool:
1933                            return to_attr in instance.__dict__
1934
1935                        is_fetched = has_cached_property
1936                else:
1937
1938                    def in_prefetched_cache(instance: Model) -> bool:
1939                        return through_attr in instance._prefetched_objects_cache
1940
1941                    is_fetched = in_prefetched_cache
1942    return prefetcher, rel_obj_descriptor, attr_found, is_fetched
1943
1944
1945def prefetch_one_level(
1946    instances: list[Model], prefetcher: Any, lookup: Prefetch, level: int
1947) -> tuple[list[Model], list[Prefetch]]:
1948    """
1949    Helper function for prefetch_related_objects().
1950
1951    Run prefetches on all instances using the prefetcher object,
1952    assigning results to relevant caches in instance.
1953
1954    Return the prefetched objects along with any additional prefetches that
1955    must be done due to prefetch_related lookups found from default managers.
1956    """
1957    # prefetcher must have a method get_prefetch_queryset() which takes a list
1958    # of instances, and returns a tuple:
1959
1960    # (queryset of instances of self.model that are related to passed in instances,
1961    #  callable that gets value to be matched for returned instances,
1962    #  callable that gets value to be matched for passed in instances,
1963    #  boolean that is True for singly related objects,
1964    #  cache or field name to assign to,
1965    #  boolean that is True when the previous argument is a cache name vs a field name).
1966
1967    # The 'values to be matched' must be hashable as they will be used
1968    # in a dictionary.
1969
1970    (
1971        rel_qs,
1972        rel_obj_attr,
1973        instance_attr,
1974        single,
1975        cache_name,
1976        is_descriptor,
1977    ) = prefetcher.get_prefetch_queryset(instances, lookup.get_current_queryset(level))
1978    # We have to handle the possibility that the QuerySet we just got back
1979    # contains some prefetch_related lookups. We don't want to trigger the
1980    # prefetch_related functionality by evaluating the query. Rather, we need
1981    # to merge in the prefetch_related lookups.
1982    # Copy the lookups in case it is a Prefetch object which could be reused
1983    # later (happens in nested prefetch_related).
1984    additional_lookups = [
1985        copy.copy(additional_lookup)
1986        for additional_lookup in getattr(rel_qs, "_prefetch_related_lookups", ())
1987    ]
1988    if additional_lookups:
1989        # Don't need to clone because the queryset should have given us a fresh
1990        # instance, so we access an internal instead of using public interface
1991        # for performance reasons.
1992        rel_qs._prefetch_related_lookups = ()
1993
1994    all_related_objects = list(rel_qs)
1995
1996    rel_obj_cache = {}
1997    for rel_obj in all_related_objects:
1998        rel_attr_val = rel_obj_attr(rel_obj)
1999        rel_obj_cache.setdefault(rel_attr_val, []).append(rel_obj)
2000
2001    to_attr, as_attr = lookup.get_current_to_attr(level)
2002    # Make sure `to_attr` does not conflict with a field.
2003    if as_attr and instances:
2004        # We assume that objects retrieved are homogeneous (which is the premise
2005        # of prefetch_related), so what applies to first object applies to all.
2006        model = instances[0].__class__
2007        try:
2008            model._model_meta.get_field(to_attr)
2009        except FieldDoesNotExist:
2010            pass
2011        else:
2012            msg = "to_attr={} conflicts with a field on the {} model."
2013            raise ValueError(msg.format(to_attr, model.__name__))
2014
2015    # Whether or not we're prefetching the last part of the lookup.
2016    leaf = len(lookup.prefetch_through.split(LOOKUP_SEP)) - 1 == level
2017
2018    for obj in instances:
2019        instance_attr_val = instance_attr(obj)
2020        vals = rel_obj_cache.get(instance_attr_val, [])
2021
2022        if single:
2023            val = vals[0] if vals else None
2024            if as_attr:
2025                # A to_attr has been given for the prefetch.
2026                setattr(obj, to_attr, val)
2027            elif is_descriptor:
2028                # cache_name points to a field name in obj.
2029                # This field is a descriptor for a related object.
2030                setattr(obj, cache_name, val)
2031            else:
2032                # No to_attr has been given for this prefetch operation and the
2033                # cache_name does not point to a descriptor. Store the value of
2034                # the field in the object's field cache.
2035                obj._state.fields_cache[cache_name] = val
2036        else:
2037            if as_attr:
2038                setattr(obj, to_attr, vals)
2039            else:
2040                queryset = getattr(obj, to_attr)
2041                if leaf and lookup.queryset is not None:
2042                    qs = queryset._apply_rel_filters(lookup.queryset)
2043                else:
2044                    # Check if queryset is a QuerySet or a related manager
2045                    # We need a QuerySet instance to cache the prefetched values
2046                    if isinstance(queryset, QuerySet):
2047                        # It's already a QuerySet, create a new instance
2048                        qs = queryset.__class__.from_model(queryset.model)
2049                    else:
2050                        # It's a related manager, get its QuerySet
2051                        # The manager's query property returns a properly filtered QuerySet
2052                        qs = queryset.query
2053                qs._result_cache = vals
2054                # We don't want the individual qs doing prefetch_related now,
2055                # since we have merged this into the current work.
2056                qs._prefetch_done = True
2057                obj._prefetched_objects_cache[cache_name] = qs
2058    return all_related_objects, additional_lookups
2059
2060
2061class RelatedPopulator:
2062    """
2063    RelatedPopulator is used for select_related() object instantiation.
2064
2065    The idea is that each select_related() model will be populated by a
2066    different RelatedPopulator instance. The RelatedPopulator instances get
2067    klass_info and select (computed in SQLCompiler) plus the used db as
2068    input for initialization. That data is used to compute which columns
2069    to use, how to instantiate the model, and how to populate the links
2070    between the objects.
2071
2072    The actual creation of the objects is done in populate() method. This
2073    method gets row and from_obj as input and populates the select_related()
2074    model instance.
2075    """
2076
2077    def __init__(self, klass_info: dict[str, Any], select: list[Any]):
2078        # Pre-compute needed attributes. The attributes are:
2079        #  - model_cls: the possibly deferred model class to instantiate
2080        #  - either:
2081        #    - cols_start, cols_end: usually the columns in the row are
2082        #      in the same order model_cls.__init__ expects them, so we
2083        #      can instantiate by model_cls(*row[cols_start:cols_end])
2084        #    - reorder_for_init: When select_related descends to a child
2085        #      class, then we want to reuse the already selected parent
2086        #      data. However, in this case the parent data isn't necessarily
2087        #      in the same order that Model.__init__ expects it to be, so
2088        #      we have to reorder the parent data. The reorder_for_init
2089        #      attribute contains a function used to reorder the field data
2090        #      in the order __init__ expects it.
2091        #  - id_idx: the index of the primary key field in the reordered
2092        #    model data. Used to check if a related object exists at all.
2093        #  - init_list: the field names fetched from the database. For
2094        #    deferred models this isn't the same as all names of the
2095        #    model's fields.
2096        #  - related_populators: a list of RelatedPopulator instances if
2097        #    select_related() descends to related models from this model.
2098        #  - local_setter, remote_setter: Methods to set cached values on
2099        #    the object being populated and on the remote object. Usually
2100        #    these are Field.set_cached_value() methods.
2101        select_fields = klass_info["select_fields"]
2102
2103        self.cols_start = select_fields[0]
2104        self.cols_end = select_fields[-1] + 1
2105        self.init_list = [
2106            f[0].target.name for f in select[self.cols_start : self.cols_end]
2107        ]
2108        self.reorder_for_init = None
2109
2110        self.model_cls = klass_info["model"]
2111        self.id_idx = self.init_list.index("id")
2112        self.related_populators = get_related_populators(klass_info, select)
2113        self.local_setter = klass_info["local_setter"]
2114        self.remote_setter = klass_info["remote_setter"]
2115
2116    def populate(self, row: tuple[Any, ...], from_obj: Model) -> None:
2117        if self.reorder_for_init:
2118            obj_data = self.reorder_for_init(row)
2119        else:
2120            obj_data = row[self.cols_start : self.cols_end]
2121        if obj_data[self.id_idx] is None:
2122            obj = None
2123        else:
2124            obj = self.model_cls.from_db(self.init_list, obj_data)
2125            for rel_iter in self.related_populators:
2126                rel_iter.populate(row, obj)
2127        self.local_setter(from_obj, obj)
2128        if obj is not None:
2129            self.remote_setter(obj, from_obj)
2130
2131
2132def get_related_populators(
2133    klass_info: dict[str, Any], select: list[Any]
2134) -> list[RelatedPopulator]:
2135    iterators = []
2136    related_klass_infos = klass_info.get("related_klass_infos", [])
2137    for rel_klass_info in related_klass_infos:
2138        rel_cls = RelatedPopulator(rel_klass_info, select)
2139        iterators.append(rel_cls)
2140    return iterators