From c0d303555a7ceb29fcaf03d067fb871476fe4c53 Mon Sep 17 00:00:00 2001 From: Stephen Burrows Date: Tue, 16 Nov 2010 16:00:07 -0500 Subject: [PATCH] Brought tests in line with mptt branch. Added assertQueryLimit method as a rough measure of efficiency. Added get_with_path tests. Made corrections to get_with_path for cases where root != None. --- fixtures/test_fixtures.json | 1210 +++++++++++++++++++++++++++++++++-- models/base.py | 18 +- tests.py | 108 ++-- 3 files changed, 1230 insertions(+), 106 deletions(-) diff --git a/fixtures/test_fixtures.json b/fixtures/test_fixtures.json index 14f5a27..4c55372 100644 --- a/fixtures/test_fixtures.json +++ b/fixtures/test_fixtures.json @@ -1,140 +1,1234 @@ [ - { - "pk": 1, - "model": "philo.tag", - "fields": { - "name": "Test tag", - "slug": "test-tag" - } - }, { "pk": 1, "model": "philo.node", "fields": { + "rght": 144, "view_object_id": 1, - "slug": "never", - "parent": 3, "view_content_type": [ "philo", - "page" - ] + "redirect" + ], + "parent": null, + "level": 0, + "lft": 1, + "tree_id": 1, + "slug": "root" } }, { "pk": 2, "model": "philo.node", "fields": { + "rght": 9, "view_object_id": 1, - "slug": "blog", - "parent": 3, "view_content_type": [ - "penfield", - "blogview" - ] + "philo", + "page" + ], + "parent": 1, + "level": 1, + "lft": 2, + "tree_id": 1, + "slug": "second" } }, { "pk": 3, "model": "philo.node", "fields": { + "rght": 8, "view_object_id": 1, - "slug": "root", - "parent": null, "view_content_type": [ "philo", - "redirect" - ] + "page" + ], + "parent": 2, + "level": 2, + "lft": 3, + "tree_id": 1, + "slug": "third" } }, { "pk": 4, "model": "philo.node", "fields": { + "rght": 7, "view_object_id": 1, - "slug": "more", - "parent": 1, "view_content_type": [ "philo", "page" - ] + ], + "parent": 3, + "level": 3, + "lft": 4, + "tree_id": 1, + "slug": "fourth" } }, { "pk": 5, "model": "philo.node", "fields": { + "rght": 6, "view_object_id": 1, - "slug": "second", - "parent": 4, "view_content_type": [ "philo", "page" - ] + ], + "parent": 4, + "level": 4, + "lft": 5, + "tree_id": 1, + "slug": "fifth" } }, { "pk": 6, "model": "philo.node", "fields": { + "rght": 143, "view_object_id": 1, - "slug": "third", - "parent": 5, "view_content_type": [ - "philo", - "page" - ] + "penfield", + "blogview" + ], + "parent": 1, + "level": 1, + "lft": 10, + "tree_id": 1, + "slug": "second2" } }, { "pk": 7, "model": "philo.node", "fields": { + "rght": 124, "view_object_id": 1, - "slug": "recursive1", - "parent": 9, "view_content_type": [ "philo", "page" - ] + ], + "parent": 6, + "level": 2, + "lft": 11, + "tree_id": 1, + "slug": "third2" } }, { "pk": 8, "model": "philo.node", "fields": { + "rght": 123, "view_object_id": 1, - "slug": "recursive2", - "parent": 7, "view_content_type": [ "philo", "page" - ] + ], + "parent": 7, + "level": 3, + "lft": 12, + "tree_id": 1, + "slug": "fourth2" } }, { "pk": 9, "model": "philo.node", "fields": { + "rght": 122, "view_object_id": 1, - "slug": "recursive3", - "parent": 8, "view_content_type": [ "philo", "page" - ] + ], + "parent": 8, + "level": 4, + "lft": 13, + "tree_id": 1, + "slug": "fifth2" } }, { "pk": 10, "model": "philo.node", "fields": { + "rght": 121, "view_object_id": 1, - "slug": "postrecursive1", + "view_content_type": [ + "philo", + "page" + ], "parent": 9, + "level": 5, + "lft": 14, + "tree_id": 1, + "slug": "0" + } + }, + { + "pk": 11, + "model": "philo.node", + "fields": { + "rght": 120, + "view_object_id": 1, "view_content_type": [ "philo", "page" - ] + ], + "parent": 10, + "level": 6, + "lft": 15, + "tree_id": 1, + "slug": "1" + } + }, + { + "pk": 12, + "model": "philo.node", + "fields": { + "rght": 119, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 11, + "level": 7, + "lft": 16, + "tree_id": 1, + "slug": "2" + } + }, + { + "pk": 13, + "model": "philo.node", + "fields": { + "rght": 118, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 12, + "level": 8, + "lft": 17, + "tree_id": 1, + "slug": "3" + } + }, + { + "pk": 14, + "model": "philo.node", + "fields": { + "rght": 117, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 13, + "level": 9, + "lft": 18, + "tree_id": 1, + "slug": "4" + } + }, + { + "pk": 15, + "model": "philo.node", + "fields": { + "rght": 116, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 14, + "level": 10, + "lft": 19, + "tree_id": 1, + "slug": "5" + } + }, + { + "pk": 16, + "model": "philo.node", + "fields": { + "rght": 115, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 15, + "level": 11, + "lft": 20, + "tree_id": 1, + "slug": "6" + } + }, + { + "pk": 17, + "model": "philo.node", + "fields": { + "rght": 114, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 16, + "level": 12, + "lft": 21, + "tree_id": 1, + "slug": "7" + } + }, + { + "pk": 18, + "model": "philo.node", + "fields": { + "rght": 113, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 17, + "level": 13, + "lft": 22, + "tree_id": 1, + "slug": "8" + } + }, + { + "pk": 19, + "model": "philo.node", + "fields": { + "rght": 112, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 18, + "level": 14, + "lft": 23, + "tree_id": 1, + "slug": "9" + } + }, + { + "pk": 20, + "model": "philo.node", + "fields": { + "rght": 111, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 19, + "level": 15, + "lft": 24, + "tree_id": 1, + "slug": "10" + } + }, + { + "pk": 21, + "model": "philo.node", + "fields": { + "rght": 110, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 20, + "level": 16, + "lft": 25, + "tree_id": 1, + "slug": "11" + } + }, + { + "pk": 22, + "model": "philo.node", + "fields": { + "rght": 109, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 21, + "level": 17, + "lft": 26, + "tree_id": 1, + "slug": "12" + } + }, + { + "pk": 23, + "model": "philo.node", + "fields": { + "rght": 108, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 22, + "level": 18, + "lft": 27, + "tree_id": 1, + "slug": "13" + } + }, + { + "pk": 24, + "model": "philo.node", + "fields": { + "rght": 107, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 23, + "level": 19, + "lft": 28, + "tree_id": 1, + "slug": "14" + } + }, + { + "pk": 25, + "model": "philo.node", + "fields": { + "rght": 106, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 24, + "level": 20, + "lft": 29, + "tree_id": 1, + "slug": "15" + } + }, + { + "pk": 26, + "model": "philo.node", + "fields": { + "rght": 105, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 25, + "level": 21, + "lft": 30, + "tree_id": 1, + "slug": "16" + } + }, + { + "pk": 27, + "model": "philo.node", + "fields": { + "rght": 104, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 26, + "level": 22, + "lft": 31, + "tree_id": 1, + "slug": "17" + } + }, + { + "pk": 28, + "model": "philo.node", + "fields": { + "rght": 73, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 27, + "level": 23, + "lft": 32, + "tree_id": 1, + "slug": "18" + } + }, + { + "pk": 29, + "model": "philo.node", + "fields": { + "rght": 72, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 28, + "level": 24, + "lft": 33, + "tree_id": 1, + "slug": "19" + } + }, + { + "pk": 30, + "model": "philo.node", + "fields": { + "rght": 71, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 29, + "level": 25, + "lft": 34, + "tree_id": 1, + "slug": "20" + } + }, + { + "pk": 31, + "model": "philo.node", + "fields": { + "rght": 70, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 30, + "level": 26, + "lft": 35, + "tree_id": 1, + "slug": "21" + } + }, + { + "pk": 32, + "model": "philo.node", + "fields": { + "rght": 69, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 31, + "level": 27, + "lft": 36, + "tree_id": 1, + "slug": "22" + } + }, + { + "pk": 33, + "model": "philo.node", + "fields": { + "rght": 68, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 32, + "level": 28, + "lft": 37, + "tree_id": 1, + "slug": "23" + } + }, + { + "pk": 34, + "model": "philo.node", + "fields": { + "rght": 67, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 33, + "level": 29, + "lft": 38, + "tree_id": 1, + "slug": "24" + } + }, + { + "pk": 35, + "model": "philo.node", + "fields": { + "rght": 66, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 34, + "level": 30, + "lft": 39, + "tree_id": 1, + "slug": "25" + } + }, + { + "pk": 36, + "model": "philo.node", + "fields": { + "rght": 65, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 35, + "level": 31, + "lft": 40, + "tree_id": 1, + "slug": "26" + } + }, + { + "pk": 37, + "model": "philo.node", + "fields": { + "rght": 64, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 36, + "level": 32, + "lft": 41, + "tree_id": 1, + "slug": "27" + } + }, + { + "pk": 38, + "model": "philo.node", + "fields": { + "rght": 63, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 37, + "level": 33, + "lft": 42, + "tree_id": 1, + "slug": "28" + } + }, + { + "pk": 39, + "model": "philo.node", + "fields": { + "rght": 62, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 38, + "level": 34, + "lft": 43, + "tree_id": 1, + "slug": "29" + } + }, + { + "pk": 40, + "model": "philo.node", + "fields": { + "rght": 61, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 39, + "level": 35, + "lft": 44, + "tree_id": 1, + "slug": "30" + } + }, + { + "pk": 41, + "model": "philo.node", + "fields": { + "rght": 60, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 40, + "level": 36, + "lft": 45, + "tree_id": 1, + "slug": "31" + } + }, + { + "pk": 42, + "model": "philo.node", + "fields": { + "rght": 59, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 41, + "level": 37, + "lft": 46, + "tree_id": 1, + "slug": "32" + } + }, + { + "pk": 43, + "model": "philo.node", + "fields": { + "rght": 58, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 42, + "level": 38, + "lft": 47, + "tree_id": 1, + "slug": "33" + } + }, + { + "pk": 44, + "model": "philo.node", + "fields": { + "rght": 57, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 43, + "level": 39, + "lft": 48, + "tree_id": 1, + "slug": "34" + } + }, + { + "pk": 45, + "model": "philo.node", + "fields": { + "rght": 56, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 44, + "level": 40, + "lft": 49, + "tree_id": 1, + "slug": "35" + } + }, + { + "pk": 46, + "model": "philo.node", + "fields": { + "rght": 55, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 45, + "level": 41, + "lft": 50, + "tree_id": 1, + "slug": "36" + } + }, + { + "pk": 47, + "model": "philo.node", + "fields": { + "rght": 54, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 46, + "level": 42, + "lft": 51, + "tree_id": 1, + "slug": "37" + } + }, + { + "pk": 48, + "model": "philo.node", + "fields": { + "rght": 53, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 47, + "level": 43, + "lft": 52, + "tree_id": 1, + "slug": "38" + } + }, + { + "pk": 49, + "model": "philo.node", + "fields": { + "rght": 103, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 27, + "level": 23, + "lft": 74, + "tree_id": 1, + "slug": "39" + } + }, + { + "pk": 50, + "model": "philo.node", + "fields": { + "rght": 102, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 49, + "level": 24, + "lft": 75, + "tree_id": 1, + "slug": "40" + } + }, + { + "pk": 51, + "model": "philo.node", + "fields": { + "rght": 101, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 50, + "level": 25, + "lft": 76, + "tree_id": 1, + "slug": "41" + } + }, + { + "pk": 52, + "model": "philo.node", + "fields": { + "rght": 100, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 51, + "level": 26, + "lft": 77, + "tree_id": 1, + "slug": "42" + } + }, + { + "pk": 53, + "model": "philo.node", + "fields": { + "rght": 99, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 52, + "level": 27, + "lft": 78, + "tree_id": 1, + "slug": "43" + } + }, + { + "pk": 54, + "model": "philo.node", + "fields": { + "rght": 98, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 53, + "level": 28, + "lft": 79, + "tree_id": 1, + "slug": "44" + } + }, + { + "pk": 55, + "model": "philo.node", + "fields": { + "rght": 97, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 54, + "level": 29, + "lft": 80, + "tree_id": 1, + "slug": "45" + } + }, + { + "pk": 56, + "model": "philo.node", + "fields": { + "rght": 96, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 55, + "level": 30, + "lft": 81, + "tree_id": 1, + "slug": "46" + } + }, + { + "pk": 57, + "model": "philo.node", + "fields": { + "rght": 95, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 56, + "level": 31, + "lft": 82, + "tree_id": 1, + "slug": "47" + } + }, + { + "pk": 58, + "model": "philo.node", + "fields": { + "rght": 94, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 57, + "level": 32, + "lft": 83, + "tree_id": 1, + "slug": "48" + } + }, + { + "pk": 59, + "model": "philo.node", + "fields": { + "rght": 93, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 58, + "level": 33, + "lft": 84, + "tree_id": 1, + "slug": "49" + } + }, + { + "pk": 60, + "model": "philo.node", + "fields": { + "rght": 92, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 59, + "level": 34, + "lft": 85, + "tree_id": 1, + "slug": "50" + } + }, + { + "pk": 61, + "model": "philo.node", + "fields": { + "rght": 91, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 60, + "level": 35, + "lft": 86, + "tree_id": 1, + "slug": "51" + } + }, + { + "pk": 62, + "model": "philo.node", + "fields": { + "rght": 90, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 61, + "level": 36, + "lft": 87, + "tree_id": 1, + "slug": "52" + } + }, + { + "pk": 63, + "model": "philo.node", + "fields": { + "rght": 89, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 62, + "level": 37, + "lft": 88, + "tree_id": 1, + "slug": "53" + } + }, + { + "pk": 64, + "model": "philo.node", + "fields": { + "rght": 142, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 6, + "level": 2, + "lft": 125, + "tree_id": 1, + "slug": "54" + } + }, + { + "pk": 65, + "model": "philo.node", + "fields": { + "rght": 141, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 64, + "level": 3, + "lft": 126, + "tree_id": 1, + "slug": "55" + } + }, + { + "pk": 66, + "model": "philo.node", + "fields": { + "rght": 140, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 65, + "level": 4, + "lft": 127, + "tree_id": 1, + "slug": "56" + } + }, + { + "pk": 67, + "model": "philo.node", + "fields": { + "rght": 139, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 66, + "level": 5, + "lft": 128, + "tree_id": 1, + "slug": "57" + } + }, + { + "pk": 68, + "model": "philo.node", + "fields": { + "rght": 138, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 67, + "level": 6, + "lft": 129, + "tree_id": 1, + "slug": "58" + } + }, + { + "pk": 69, + "model": "philo.node", + "fields": { + "rght": 137, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 68, + "level": 7, + "lft": 130, + "tree_id": 1, + "slug": "59" + } + }, + { + "pk": 70, + "model": "philo.node", + "fields": { + "rght": 136, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 69, + "level": 8, + "lft": 131, + "tree_id": 1, + "slug": "60" + } + }, + { + "pk": 71, + "model": "philo.node", + "fields": { + "rght": 135, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 70, + "level": 9, + "lft": 132, + "tree_id": 1, + "slug": "61" + } + }, + { + "pk": 72, + "model": "philo.node", + "fields": { + "rght": 134, + "view_object_id": 1, + "view_content_type": [ + "philo", + "page" + ], + "parent": 71, + "level": 10, + "lft": 133, + "tree_id": 1, + "slug": "62" + } + }, + { + "pk": 1, + "model": "philo.tag", + "fields": { + "name": "Test tag", + "slug": "test-tag" } }, { @@ -142,7 +1236,7 @@ "model": "philo.redirect", "fields": { "status_code": 302, - "target": "never" + "target": "second" } }, { @@ -150,10 +1244,14 @@ "model": "philo.template", "fields": { "mimetype": "text/html", + "rght": 2, "code": "Never is working!\r\n{% node_url %}", "name": "Never", "parent": null, + "level": 0, "documentation": "", + "lft": 1, + "tree_id": 1, "slug": "never" } }, @@ -162,10 +1260,14 @@ "model": "philo.template", "fields": { "mimetype": "text/html", - "code": "An index page!\r\n{% node_url %}\r\n\r\n{% for entry in entries %}\r\n

{{ entry.title }}

\r\n
\r\n{{ entry.content }}\r\n
\r\n{% endfor %}", + "rght": 2, + "code": "An index page!\r\n{% node_url %}\r\n{% for entry in entries %}\r\n

{{ entry.title }}

\r\n
\r\n{{ entry.content }}\r\n
\r\n{% endfor %}", "name": "Index", "parent": null, + "level": 0, "documentation": "", + "lft": 1, + "tree_id": 2, "slug": "index" } }, @@ -174,10 +1276,14 @@ "model": "philo.template", "fields": { "mimetype": "text/html", + "rght": 2, "code": "Entry detail page.", - "name": "Entry", + "name": "Entry Detail Page", "parent": null, + "level": 0, "documentation": "", + "lft": 1, + "tree_id": 3, "slug": "entry" } }, @@ -186,10 +1292,14 @@ "model": "philo.template", "fields": { "mimetype": "text/html", + "rght": 2, "code": "Tag page!", "name": "Tag", "parent": null, + "level": 0, "documentation": "", + "lft": 1, + "tree_id": 4, "slug": "tag" } }, @@ -198,10 +1308,14 @@ "model": "philo.template", "fields": { "mimetype": "text/html", + "rght": 2, "code": "Entry archive page!", "name": "Entry Archives!", "parent": null, + "level": 0, "documentation": "", + "lft": 1, + "tree_id": 5, "slug": "entry-archives" } }, @@ -210,10 +1324,14 @@ "model": "philo.template", "fields": { "mimetype": "text/html", + "rght": 2, "code": "tag archives...", "name": "Tag Archives", "parent": null, + "level": 0, "documentation": "", + "lft": 1, + "tree_id": 6, "slug": "tag-archives" } }, diff --git a/models/base.py b/models/base.py index ce74489..37ab247 100644 --- a/models/base.py +++ b/models/base.py @@ -328,9 +328,6 @@ class TreeManager(models.Manager): kwargs["%s%s__exact" % (prefix, field)] = segment prefix += "parent__" - if not prefix and root is not None: - prefix = "parent__" - if prefix: kwargs[prefix[:-2]] = root @@ -342,13 +339,15 @@ class TreeManager(models.Manager): path += pathsep return path - def find_obj(segments, depth, deepest_found): + def find_obj(segments, depth, deepest_found=None): if deepest_found is None: deepest_level = 0 - else: + elif root is None: deepest_level = deepest_found.get_level() + 1 + else: + deepest_level = deepest_found.get_level() - root.get_level() try: - obj = self.get(**make_query_kwargs(segments[deepest_level:depth], deepest_found)) + obj = self.get(**make_query_kwargs(segments[deepest_level:depth], deepest_found or root)) except self.model.DoesNotExist: if not deepest_level and depth > 1: # make sure there's a root node... @@ -364,7 +363,10 @@ class TreeManager(models.Manager): return find_obj(segments, depth, deepest_found) else: # Yay! Found one! - deepest_level = obj.get_level() + 1 + if root is None: + deepest_level = obj.get_level() + 1 + else: + deepest_level = obj.get_level() - root.get_level() # Could there be a deeper one? if obj.is_leaf_node(): @@ -391,7 +393,7 @@ class TreeManager(models.Manager): # can be reduced. It might be possible to weight the search towards the beginning # of the path, since short paths are more likely, but how far forward? It would # need to shift depending on len(segments) - perhaps logarithmically? - return find_obj(segments, len(segments)/2 or len(segments), root) + return find_obj(segments, len(segments)/2 or len(segments)) class TreeModel(MPTTModel): diff --git a/tests.py b/tests.py index 874f62f..7d5fc45 100644 --- a/tests.py +++ b/tests.py @@ -1,6 +1,7 @@ from django.test import TestCase from django import template from django.conf import settings +from django.db import connection from philo.exceptions import AncestorDoesNotExist from philo.models import Node, Page, Template from philo.contrib.penfield.models import Blog, BlogView, BlogEntry @@ -18,25 +19,25 @@ class NodeURLTestCase(TestCase): command.handle(all_apps=True) self.templates = [ - ("{% node_url %}", "/root/never/"), - ("{% node_url for node2 %}", "/root/blog/"), - ("{% node_url as hello %}

{{ hello|slice:'1:' }}

", "

root/never/

"), - ("{% node_url for nodes|first %}", "/root/never/"), + ("{% node_url %}", "/root/second/"), + ("{% node_url for node2 %}", "/root/second2/"), + ("{% node_url as hello %}

{{ hello|slice:'1:' }}

", "

root/second/

"), + ("{% node_url for nodes|first %}", "/root/"), ("{% node_url with entry %}", settings.TEMPLATE_STRING_IF_INVALID), - ("{% node_url with entry for node2 %}", "/root/blog/2010/10/20/first-entry"), - ("{% node_url with tag for node2 %}", "/root/blog/tags/test-tag/"), - ("{% node_url with date for node2 %}", "/root/blog/2010/10/20"), - ("{% node_url entries_by_day year=date|date:'Y' month=date|date:'m' day=date|date:'d' for node2 as goodbye %}{{ goodbye|upper }}", "/ROOT/BLOG/2010/10/20"), - ("{% node_url entries_by_month year=date|date:'Y' month=date|date:'m' for node2 %}", "/root/blog/2010/10"), - ("{% node_url entries_by_year year=date|date:'Y' for node2 %}", "/root/blog/2010/"), + ("{% node_url with entry for node2 %}", "/root/second2/2010/10/20/first-entry"), + ("{% node_url with tag for node2 %}", "/root/second2/tags/test-tag/"), + ("{% node_url with date for node2 %}", "/root/second2/2010/10/20"), + ("{% node_url entries_by_day year=date|date:'Y' month=date|date:'m' day=date|date:'d' for node2 as goodbye %}{{ goodbye|upper }}", "/ROOT/SECOND2/2010/10/20"), + ("{% node_url entries_by_month year=date|date:'Y' month=date|date:'m' for node2 %}", "/root/second2/2010/10"), + ("{% node_url entries_by_year year=date|date:'Y' for node2 %}", "/root/second2/2010/"), ] nodes = Node.objects.all() blog = Blog.objects.all()[0] self.context = template.Context({ - 'node': nodes[0], - 'node2': nodes[1], + 'node': nodes.get(slug='second'), + 'node2': nodes.get(slug='second2'), 'nodes': nodes, 'entry': BlogEntry.objects.all()[0], 'tag': blog.entry_tags.all()[0], @@ -57,52 +58,55 @@ class TreePathTestCase(TestCase): command = Command() command.handle(all_apps=True) - def test_has_ancestor(self): + def assertQueryLimit(self, max, expected_result, *args, **kwargs): + # As a rough measure of efficiency, limit the number of queries required for a given operation. + settings.DEBUG = True + try: + queries = len(connection.queries) + if isinstance(expected_result, type) and issubclass(expected_result, Exception): + self.assertRaises(expected_result, Node.objects.get_with_path, *args, **kwargs) + else: + self.assertEqual(Node.objects.get_with_path(*args, **kwargs), expected_result) + queries = len(connection.queries) - queries + if queries > max: + raise AssertionError('"%d" unexpectedly not less than or equal to "%s"' % (queries, max)) + finally: + settings.DEBUG = False + + def test_get_with_path(self): root = Node.objects.get(slug='root') third = Node.objects.get(slug='third') - r1 = Node.objects.get(slug='recursive1') - r2 = Node.objects.get(slug='recursive2') - pr1 = Node.objects.get(slug='postrecursive1') + second2 = Node.objects.get(slug='second2') + fifth = Node.objects.get(slug='fifth') + e = Node.DoesNotExist - # Simple case: straight path - self.assertEqual(third.has_ancestor(root), True) - self.assertEqual(root.has_ancestor(root), False) - self.assertEqual(root.has_ancestor(None), True) - self.assertEqual(third.has_ancestor(None), True) - self.assertEqual(root.has_ancestor(root, inclusive=True), True) + # Empty segments + self.assertQueryLimit(0, root, '', root=root) + self.assertQueryLimit(0, e, '') + self.assertQueryLimit(0, (root, None), '', root=root, absolute_result=False) - # Recursive case - self.assertEqual(r1.has_ancestor(r1), True) - self.assertEqual(r1.has_ancestor(r2), True) - self.assertEqual(r2.has_ancestor(r1), True) - self.assertEqual(r2.has_ancestor(None), False) + # Absolute result + self.assertQueryLimit(1, third, 'root/second/third') + self.assertQueryLimit(1, third, 'second/third', root=root) + self.assertQueryLimit(1, third, 'root//////second/third///') - # Post-recursive case - self.assertEqual(pr1.has_ancestor(r1), True) - self.assertEqual(pr1.has_ancestor(pr1), False) - self.assertEqual(pr1.has_ancestor(pr1, inclusive=True), True) - self.assertEqual(pr1.has_ancestor(None), False) - self.assertEqual(pr1.has_ancestor(root), False) - - def test_get_path(self): - root = Node.objects.get(slug='root') - third = Node.objects.get(slug='third') - r1 = Node.objects.get(slug='recursive1') - r2 = Node.objects.get(slug='recursive2') - pr1 = Node.objects.get(slug='postrecursive1') + self.assertQueryLimit(1, e, 'root/secont/third') + self.assertQueryLimit(1, e, 'second/third') - # Simple case: straight path to None - self.assertEqual(root.get_path(), 'root') - self.assertEqual(third.get_path(), 'root/never/more/second/third') + # Non-absolute result (binary search) + self.assertQueryLimit(2, (second2, 'sub/path/tail'), 'root/second2/sub/path/tail', absolute_result=False) + self.assertQueryLimit(3, (second2, 'sub/'), 'root/second2/sub/', absolute_result=False) + self.assertQueryLimit(2, e, 'invalid/path/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/0', absolute_result=False) + self.assertQueryLimit(1, (root, None), 'root', absolute_result=False) + self.assertQueryLimit(2, (second2, None), 'root/second2', absolute_result=False) + self.assertQueryLimit(3, (third, None), 'root/second/third', absolute_result=False) - # Recursive case: Looped path to root None - self.assertEqual(r1.get_path(), u'\u2026/recursive1/recursive2/recursive3/recursive1') - self.assertEqual(pr1.get_path(), u'\u2026/recursive3/recursive1/recursive2/recursive3/postrecursive1') + # with root != None + self.assertQueryLimit(1, (second2, None), 'second2', root=root, absolute_result=False) + self.assertQueryLimit(2, (third, None), 'second/third', root=root, absolute_result=False) - # Simple error case: straight invalid path - self.assertRaises(AncestorDoesNotExist, root.get_path, root=third) - self.assertRaises(AncestorDoesNotExist, third.get_path, root=pr1) + # Preserve trailing slash + self.assertQueryLimit(2, (second2, 'sub/path/tail/'), 'root/second2/sub/path/tail/', absolute_result=False) - # Recursive error case - self.assertRaises(AncestorDoesNotExist, r1.get_path, root=root) - self.assertRaises(AncestorDoesNotExist, pr1.get_path, root=third) \ No newline at end of file + # Speed increase for leaf nodes - should this be tested? + self.assertQueryLimit(1, (fifth, 'sub/path/tail/len/five'), 'root/second/third/fourth/fifth/sub/path/tail/len/five', absolute_result=False) \ No newline at end of file -- 2.20.1