Opened 3 weeks ago

Last modified 10 days ago

#37115 assigned New feature

Add support for Generic Relations / Table-Valued Expressions in the ORM

Reported by: Pravin Owned by: Pravin
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords: Table-Valued expressions, Set-returning functions, SRF, generate_series, Postgres, Orm
Cc: Pravin, Lily, Simon Charette, Bhuvnesh, David Sanders, Shai Berger Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Pravin)

This ticket proposes the implementation of a generic Relation API within the Django ORM to support Table-Valued Expressions (TVEs) and functions that return sets of rows.

A generic Relation API will lay the groundwork for cleanly implementing several advanced querying features across different databases, including:

  • PostgreSQL generate_series() (and potential equivalents for other backends).
  • Subqueries acting as derived tables directly within the FROM clause.
  • Database abstraction for json_each() , JSON_TABLE and json_array_elements().
  • Deprecation of FilteredRelation.

References & Context

Change History (9)

comment:1 by Pravin, 3 weeks ago

Description: modified (diff)

comment:2 by Jacob Walls, 3 weeks ago

Cc: Lily Simon Charette Bhuvnesh added
Keywords: Table-Valued Set-returning added; Table Value Set returning removed
Summary: Title: Add support for Generic Relations / Table-Valued Expressions in the ORMAdd support for Generic Relations / Table-Valued Expressions in the ORM
Triage Stage: UnreviewedAccepted
Version: 6.0dev

Thanks. Just clarifying that Subquery is probably the easiest tool for validating the approach; the other bullet points mentioned above should probably get their own separate tickets later.

comment:3 by Jacob Walls, 3 weeks ago

Cc: David Sanders added

comment:4 by Simon Charette, 3 weeks ago

As mentioned in a few locations already (forum, discord, github) I think that in order to even consider adding this feature we must add support for a generic CompositeField. We don't have a ticket for that but Lilly did some exploration work for it here that predated adding support for CompositePrimaryKey.

The reason is simple, we need a way to adequately represent the output_field of these Expression to remove the hack we have right now on sql.Query.output_field. Once we have that the problem of supporting table-like expressions becomes much simpler as we can make members of sql.Query.alias_map (which hosts table-like references) subclasses of Expression instead of opaque BaseTable and Join datastructures and augment them with compilation directives such as where they should live (inlined in the FROM clause, as a CTE) and how they should be combined (e.g. LATERAL JOIN)

From there things like

Author.objects.alias(
   book=Books.objects.values("title", "number_of_pages")
)

become much easier to implement as any expression that has .output_field.is_composite can be treated a candidate for alias_map inclusion.

comment:5 by Jacob Walls, 2 weeks ago

Wonderful. Here's one forum post where Simon fleshes this idea out at more length.

Pravin started iterating on a design in a markdown document. In it, there was a first swing at representing a composite field with a columns dict, and then some ideas about "intercepting" this later, but I agree that Simon's proposal is more idiomatic, more general, and opens more doors.

Pravin, would you be open to reimagining your design document as a small-ish DEP that we could iterate on via a pull request workflow? From the experience doing something similar with the MAILERS implementation in Django 6.1, this won't arrest progress on the implementation, as you can be iterating on a proof-of-concept in parallel.

comment:6 by Pravin, 2 weeks ago

Sound great, Yeah I will reform my design into small DEP .
Thank you.

comment:7 by Shai Berger, 2 weeks ago

Cc: Shai Berger added

It seems like this may be related to the suggestion to add CTE support to the ORM.

comment:8 by Simon Charette, 2 weeks ago

It seems like this may be related to the ​suggestion to add CTE support to the ORM.

I believe so. The moment we have

  1. A way to express a tuple of expressions (CompositeField) as Expression.output_field
  2. Adapted BaseTable and Join machinery to take advantage of 1.

The only part missing to add support for CTE is to allow compilation directives to be attached to table like objects (e.g. a TableExpression(Expression).output_field: CompositeField that would serve as a base class for BaseTable and Join) to inform the compilation layer (compiler.SQLCompiler) that the resulting SQL should prefix the query instead of being inlined in the FROM clause.

Last edited 2 weeks ago by Simon Charette (previous) (diff)

comment:9 by Jacob Walls, 10 days ago

Feedback on draft DEP welcome.

Note: See TracTickets for help on using tickets.
Back to Top