google-code-export / django-mptt

Automatically exported from code.google.com/p/django-mptt
Other
0 stars 0 forks source link

[has patch] add_related_count() can accept related querysets, not related model. #38

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
This makes it much more usable. I'll show why.

Old fashion:

Model.tree.add_related_count(Model.objects.all(), AnotherModel, 'rel_col', 
'cnt', cumulative=True) makes this query:

SELECT (SELECT COUNT(*) FROM `another_model` WHERE (
    `rel_col_id` IN
    (
        SELECT m2.`id`
        FROM `model` m2
        WHERE m2.`mptt_tree_id` = `model`.`mptt_tree_id`
          AND m2.`mptt_left` BETWEEN `model`.`mptt_left`
                              AND `model`.`mptt_right`
    )
)) AS `cnt`, `col1`, `colN` FROM `model`

Good, but we cant change add more difficult subquery. My patch allows to 
use related querysets instead of related model (which being determined 
automatically).

Model.tree.add_related_count(Model.objects.all(), AnotherModel.objects.all
(), 'rel_col', 'cnt', cumulative=True) makes exactly the same query. But 
this:

Model.tree.add_related_count(Model.objects.all(), 
AnotherModel.objects.filter(field=1).filter(field=2), 'rel_col', 'cnt', 
cumulative=True) makes this:

SELECT (SELECT COUNT(*) FROM `another_model` WHERE `field` = 1 AND `field` 
= 2 AND (
    `field` = 2 AND
    `field` = 
    `rel_col_id` IN
    (
        SELECT m2.`id`
        FROM `model` m2
        WHERE m2.`mptt_tree_id` = `model`.`mptt_tree_id`
          AND m2.`mptt_left` BETWEEN `model`.`mptt_left`
                              AND `model`.`mptt_right`
    )
)) AS `cnt`, `col1`, `colN` FROM `model`

In my case: I have categories, tasks and users. With my patch I'm able to 
fill task counts for specified user in all categories :). Even more! Using 
non-documented "having" ability in django orm queries, I can select all 
categories which have >0 tasks for specified user. E.g.:

qs = AnotherModel.objects.filter(field=1).filter(field=2), 'rel_col', 
'cnt', cumulative=True)
qs.query.having.append('%s > %s' % (connection.ops.quote_name('cnt'), 0))

Which will have a result:

SELECT (SELECT COUNT(*) FROM `another_model` WHERE `field` = 1 AND `field` 
= 2 AND (
    `field` = 2 AND
    `field` = 
    `rel_col_id` IN
    (
        SELECT m2.`id`
        FROM `model` m2
        WHERE m2.`mptt_tree_id` = `model`.`mptt_tree_id`
          AND m2.`mptt_left` BETWEEN `model`.`mptt_left`
                              AND `model`.`mptt_right`
    )
)) AS `cnt`, `col1`, `colN` FROM `model` HAVING `cnt` > 0

All of these examples are for cumulative queries. But also apply to non-
cumulative queries as well. Woohooo! :)

Original issue reported on code.google.com by mocksoul on 5 Dec 2008 at 11:03

Attachments:

GoogleCodeExporter commented 9 years ago
btw, I was thinking that such mptt technique will not be available with django 
orm. 
Nice :).

Original comment by mocksoul on 5 Dec 2008 at 11:04

GoogleCodeExporter commented 9 years ago
Oh yes, templatetags should be fixed for this patch.

Original comment by mocksoul on 5 Dec 2008 at 11:14

GoogleCodeExporter commented 9 years ago
This will fix templatetags, althouth with no ability to utilize my patch 
features.

=== modified file 'mptt/utils.py'
--- mptt/utils.py       2008-12-05 00:17:36 +0000
+++ mptt/utils.py       2008-12-05 23:16:07 +0000
@@ -128,7 +128,7 @@
     """
     if rel_cls and rel_field and count_attr:
         children = node._tree_manager.add_related_count(
-            node.get_children(), rel_cls, rel_field, count_attr, cumulative)
+            node.get_children(), rel_cls.objects.all(), rel_field, count_attr, 
cumulative)
     else:
         children = node.get_children()
     return itertools.chain(node.get_ancestors(), [node], children)

Original comment by mocksoul on 5 Dec 2008 at 11:17

GoogleCodeExporter commented 9 years ago
mocksoul

Could this be accomplished with annotate() in Django 1.1+ ?

Thanks

Original comment by craig.ds@gmail.com on 3 Sep 2010 at 12:23

GoogleCodeExporter commented 9 years ago
Indeed it looks like annotate would provide similar/same functionality but the 
performance/queries should be tested - as to which implementation (this patch 
or annotate) gives better performance.
I hope mocksoul is still interested in this and can shed a bit of light on this 
matter.

Original comment by matjaz.c...@gmail.com on 7 Sep 2010 at 12:51

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Migrated to https://github.com/django-mptt/django-mptt/issues#issue/62

Original comment by craig.ds@gmail.com on 19 Dec 2010 at 1:06