| 623 | |
| 624 | |
| 625 | def get_serializer() -> Callable: |
| 626 | def serialize( |
| 627 | self: "Model", |
| 628 | value: Optional["Model"], |
| 629 | handler: SerializerFunctionWrapHandler, |
| 630 | ) -> Any: |
| 631 | """ |
| 632 | Serialize a value if it's not expired weak reference. |
| 633 | """ |
| 634 | try: |
| 635 | try: |
| 636 | with warnings.catch_warnings(): |
| 637 | warnings.filterwarnings( |
| 638 | "ignore", message="Pydantic serializer warnings" |
| 639 | ) |
| 640 | return handler(value) |
| 641 | except ValueError as exc: |
| 642 | if not str(exc).startswith("Circular reference"): |
| 643 | raise exc |
| 644 | # Pydantic >= 2.13 dispatches the wrap serializer with |
| 645 | # broader value types (e.g. QuerysetProxy for M2M reverse |
| 646 | # accessors) where 2.12 unwrapped to Model first. Earlier |
| 647 | # pydantic versions never reach this branch with a non- |
| 648 | # Model value, so the None return is uncovered on the |
| 649 | # 2.11 floor pinned in CI. |
| 650 | if value is None or not hasattr(value, "ormar_config"): |
| 651 | return None # pragma: no cover |
| 652 | return {value.ormar_config.pkname: value.pk} |
| 653 | except ReferenceError: |
| 654 | return None |
| 655 | |
| 656 | return serialize |
| 657 | |
| 658 | |
| 659 | class ModelMetaclass(pydantic._internal._model_construction.ModelMetaclass): |