feincms / django-tree-queries

Adjacency-list trees for Django using recursive common table expressions. Supports PostgreSQL, sqlite, MySQL and MariaDB.
https://django-tree-queries.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
427 stars 27 forks source link

Add the ability to filter queries before construction of the CTE #66

Closed rhomboss closed 6 months ago

rhomboss commented 6 months ago
rhomboss commented 6 months ago

This addresses issue #50 and also addresses a possible bug where sibling ordering was persisting between queries even when no explicit ordering was given because it was being stored as a class variable.

It should be noted that filtering prior to the construction of the CTE means that filtered status is inherited i.e. if a parent is excluded so too will all of its descendants. This contrasts with a normal filter which when applied after the CTE is built will retain the descendants of an excluded parent if those descendants meet the filtering criteria.

rhomboss commented 6 months ago

If you think tree_filter is a better name I can change it. When I was writing this over the weekend I really only thought of the filter as something that applied to the tree earlier than the normal filter.

I had completely forgotten about Q objects. Using them exclusively won't really simplify the code any since all that really happens is the arguments of pre_filter gets passed directly into django's normal queryset .filter. That being said I did forget to add support for Q objects which is a pretty easy fix. I just have to make sure that pre_filter passes both *args and **kwargs instead of just **kwargs.

rhomboss commented 6 months ago

I had an idea for how to simplify this feature by making the Django ORM generate the entire __rank_table by itself. I'm still investigating but it looks promising and should simplify any future API extensions that involve the __rank_table so don't commit any of my changes just yet!

rhomboss commented 6 months ago

I've simplified the code by adding the instance variable called rank_table_query. This is a default Django queryset that can be used to generate the CTE's __rank_table sql. Now, the tree_filter and tree_exclude methods simply apply Django's normal queryset methods to the rank_table_query. And, in the future if there is need to allow users to further modify the __rank_table beyond basic filtering you only have to expose the appropriate Django queryset function with the API.

matthiask commented 6 months ago

Thank you!