Create a model instance without validation, DB checks, or FK restrictions. This creates a "detached" instance that has the right shape for reading attributes and iterating relations, but is not part of the ORM lifecycle. Useful for unit testing and serialization wit
(cls: type[MODEL], _saved_in_db: bool = False, **kwargs: Any)
| 940 | |
| 941 | @classmethod |
| 942 | def construct(cls: type[MODEL], _saved_in_db: bool = False, **kwargs: Any) -> MODEL: |
| 943 | """ |
| 944 | Create a model instance without validation, DB checks, or FK restrictions. |
| 945 | |
| 946 | This creates a "detached" instance that has the right shape for reading |
| 947 | attributes and iterating relations, but is not part of the ORM lifecycle. |
| 948 | Useful for unit testing and serialization without a database connection. |
| 949 | |
| 950 | Unlike ``__init__``, this method: |
| 951 | - Does NOT validate field values (nullability, type checks) |
| 952 | - Does NOT require FK objects to be saved to the database |
| 953 | - Does NOT prevent setting backward FK, backward O2O, or M2M fields |
| 954 | - Does NOT call ``to_python_value`` on data fields |
| 955 | - Skips async defaults (sets them to ``None``) |
| 956 | |
| 957 | Backward FK and M2M fields are wrapped in ``ReverseRelation`` and |
| 958 | ``ManyToManyRelation`` respectively with ``_fetched=True`` so that |
| 959 | iteration, ``len()``, ``in``, and ``bool()`` work without raising |
| 960 | ``NoValuesFetched``. |
| 961 | |
| 962 | Example:: |
| 963 | |
| 964 | tournament = Tournament.construct(id=1, name="Test") |
| 965 | event = Event.construct( |
| 966 | name="Game", |
| 967 | tournament=tournament, |
| 968 | participants=[ |
| 969 | Team.construct(id=1, name="Team A"), |
| 970 | Team.construct(id=2, name="Team B"), |
| 971 | ], |
| 972 | ) |
| 973 | assert event.tournament.name == "Test" |
| 974 | assert event.tournament_id == 1 |
| 975 | assert len(event.participants) == 2 |
| 976 | |
| 977 | :param _saved_in_db: Whether to mark the instance as saved in DB. |
| 978 | Defaults to ``False``. |
| 979 | :param kwargs: Field values to set on the instance. |
| 980 | :return: A new model instance with the given field values. |
| 981 | """ |
| 982 | self = cls.__new__(cls) |
| 983 | meta = self._meta |
| 984 | _setattr = object.__setattr__ |
| 985 | |
| 986 | _setattr(self, "_partial", False) |
| 987 | _setattr(self, "_saved_in_db", _saved_in_db) |
| 988 | _setattr(self, "_custom_generated_pk", False) |
| 989 | _setattr(self, "_await_when_save", {}) |
| 990 | |
| 991 | # Track source fields that are auto-populated from FK/O2O objects |
| 992 | # so that the default-setting loop doesn't overwrite them with None. |
| 993 | populated_source_fields: set[str] = set() |
| 994 | |
| 995 | for key, value in kwargs.items(): |
| 996 | if key in meta.backward_fk_fields: |
| 997 | # Backward FK: wrap in ReverseRelation with _fetched=True |
| 998 | backward_fk: BackwardFKRelation = meta.fields_map[key] # type: ignore |
| 999 | rel = ReverseRelation( |