()
| 65 | |
| 66 | |
| 67 | async def run(): |
| 68 | await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]}) |
| 69 | await Tortoise.generate_schemas() |
| 70 | |
| 71 | # Create test data |
| 72 | engineering = await Department.create(name="Engineering") |
| 73 | await Employee.create(name="Alice", department=engineering) |
| 74 | await Employee.create(name="Bob", department=engineering) |
| 75 | await Employee.create(name="Charlie") # no department (nullable FK) |
| 76 | |
| 77 | # ────────────────────────────────────────────────────────────────────── |
| 78 | # Section 1: Nullable FK is Optional in the Pydantic schema |
| 79 | # |
| 80 | # A nullable ForeignKeyField generates a pydantic field with |
| 81 | # "default": null that is NOT in "required". |
| 82 | # ────────────────────────────────────────────────────────────────────── |
| 83 | print("=" * 70) |
| 84 | print("Section 1: Nullable FK is Optional") |
| 85 | print("=" * 70) |
| 86 | |
| 87 | Employee_Pydantic = pydantic_model_creator(Employee) |
| 88 | schema = Employee_Pydantic.model_json_schema() |
| 89 | print(json.dumps(schema, indent=4)) |
| 90 | |
| 91 | # The 'department' field has "default": null and is NOT in "required" |
| 92 | required = schema.get("required", []) |
| 93 | print(f"\nRequired fields: {required}") |
| 94 | print("'department' in required:", "department" in required) |
| 95 | |
| 96 | dept_props = schema.get("properties", {}).get("department", {}) |
| 97 | has_default_null = dept_props.get("default") is None and "default" in dept_props |
| 98 | print(f"'department' has default null: {has_default_null}") |
| 99 | |
| 100 | # ────────────────────────────────────────────────────────────────────── |
| 101 | # Section 2: Computed field with included relation (auto-prefetched) |
| 102 | # |
| 103 | # When the 'employees' reverse relation is included in the pydantic |
| 104 | # model, from_tortoise_orm() auto-prefetches it. Both computed fields |
| 105 | # work because the relation data is available. |
| 106 | # ────────────────────────────────────────────────────────────────────── |
| 107 | print("\n" + "=" * 70) |
| 108 | print("Section 2: Computed field with included relation") |
| 109 | print("=" * 70) |
| 110 | |
| 111 | Department_Pydantic = pydantic_model_creator(Department) |
| 112 | |
| 113 | dept = await Department.get(name="Engineering") |
| 114 | dept_pydantic = await Department_Pydantic.from_tortoise_orm(dept) |
| 115 | print(dept_pydantic.model_dump_json(indent=4)) |
| 116 | |
| 117 | # Both computed fields work because the relation was auto-prefetched |
| 118 | print(f"\nemployee_count: {dept_pydantic.employee_count}") |
| 119 | print(f"employee_names: {dept_pydantic.employee_names}") |
| 120 | |
| 121 | # ────────────────────────────────────────────────────────────────────── |
| 122 | # Section 3: Computed field with excluded relation + manual prefetch |
| 123 | # |
| 124 | # The 'employees' relation is excluded from the pydantic model (so it |
no test coverage detected