To add to what @jacobtylerwalls said I think that very minimal typing around the introduction of two typing.Protocol could go a long way in making the ORM more approachable
from __future__ import annotations
from typing import Protocol
from django.db.models import fields
from django.db.models.sql import compiler, query
class Compilable(Protocol):
"""
Object that can be compiled to a PEP 249 compliant tuple comprised of
a SQL string and its associated parameters sequence.
It can optionally have `as_vendor` methods defined to specialize the
compilation on different backends (e.g. `as_postgres`).
"""
def get_source_expressions(self) -> list[Compilable | None]: ...
def as_sql(
self, compiler: compiler.SQLCompiler, connection
) -> tuple[str, tuple]: ...
class Resolvable(Protocol):
"""
Object that can resolve any field and transform reference it has in
the context of a query and return an object ready to be compiled for
execution.
"""
output_field: fields.Field
def get_source_expressions(self) -> list[Resolvable | None]: ...
def resolve_expression(
self,
query: query.Query,
allow_joins: bool = True,
reuse: set[str] | None = None,
summarize: bool = False,
for_save: bool = False,
) -> Compilable: ...