Query Method Behavior Reference
Summary
Warning
All query methods (filter(), exclude(), get(), exists(), etc.) operate on
direct children only by default, equivalent to calling .children() first.
To search nested elements, you must explicitly call .all() before the query method.
Core Principle
# These are equivalent:
kml.placemarks.filter(name="Example") # Searches direct children only
kml.placemarks.children().filter(name="Example") # Explicitly searches direct children only
# To search ALL elements including nested:
kml.placemarks.all().filter(name="Example") # Searches ALL placemarks including nested
Truth Table for Query Methods
Manager Type |
Query Method |
Default Scope |
Equivalent To |
To Search All Nested |
|---|---|---|---|---|
|
|
Direct children only |
|
|
|
|
Direct children only |
|
|
|
|
Direct children only |
|
|
|
|
Direct children only |
|
|
|
|
Direct children only |
|
|
|
|
Direct children only |
|
|
|
|
Direct children only |
|
|
Behavior by Element Type
KMLFile Root Managers
Manager |
Default Query Scope |
Notes |
|---|---|---|
|
Root-level placemarks only |
Does NOT search placemarks inside folders |
|
Root-level folders only |
Does NOT search nested subfolders |
|
Root-level standalone Points only |
Does NOT include Points from Placemarks or nested folders |
|
Root-level standalone Paths only |
Does NOT include Paths from Placemarks or nested folders |
|
Root-level standalone Polygons only |
Does NOT include Polygons from Placemarks or nested folders |
Folder Managers
Manager |
Default Query Scope |
Notes |
|---|---|---|
|
Direct child placemarks only |
Does NOT search placemarks in subfolders |
|
Direct subfolders only |
Does NOT search deeper nested folders |
|
Direct child standalone Points only |
Does NOT include Points from child Placemarks or subfolders |
|
Direct child standalone Paths only |
Does NOT include Paths from child Placemarks or subfolders |
|
Direct child standalone Polygons only |
Does NOT include Polygons from child Placemarks or subfolders |
Special Cases
Context |
Behavior |
|---|---|
|
Filters Points within this MultiGeometry only |
|
Filters Paths within this MultiGeometry only |
|
Filters Polygons within this MultiGeometry only |
Real-World Examples
Example 1: Finding a Placemark by Name
# WRONG - Only searches root level:
placemark = kml.placemarks.get(name="Store #42")
# Raises KMLElementNotFound if Store #42 is in a folder
# CORRECT - Searches all placemarks:
placemark = kml.placemarks.all().get(name="Store #42")
# Finds Store #42 wherever it is
Example 2: Counting Elements
# Count only root-level placemarks:
root_count = kml.placemarks.count() # e.g., returns 5
# Count ALL placemarks including nested:
total_count = kml.placemarks.all().count() # e.g., returns 150
Example 3: Filtering Visible Placemarks
# Only root-level visible placemarks:
visible_root = kml.placemarks.filter(visibility=True)
# ALL visible placemarks including nested:
all_visible = kml.placemarks.all().filter(visibility=True)
Example 4: Geometry Collection
# Get only standalone Points at root level:
root_points = kml.points.filter(altitude__gt=100)
# Get ALL Points including those from Placemarks and nested folders:
all_high_points = kml.points.all().filter(altitude__gt=100)
Implementation Details
The reason for this behavior is in the manager implementation:
def filter(self, **kwargs):
return self.get_queryset().filter(**kwargs)
# get_queryset() returns direct children only
def get_queryset(self):
return KMLQuerySet(self.elements)
# self.elements contains direct children only
The .all() method explicitly collects nested elements:
def all(self):
all_elements = list(self.elements) # Start with direct children
all_elements.extend(self._collect_nested_elements()) # Add nested
return KMLQuerySet(all_elements)
Best Practices
Always use
.all()when searching entire KML documents:# Searching for any placemark named "Target" results = kml.placemarks.all().filter(name__icontains="Target")
Use direct query methods only when you specifically want root/direct children:
# When you explicitly want only root-level folders root_folders = kml.folders.filter(visibility=True)
Be explicit about scope for clarity:
# Clear intent - searching only direct children direct_children = folder.placemarks.children().filter(visibility=True) # Clear intent - searching all nested elements all_nested = folder.placemarks.all().filter(visibility=True)
Remember geometry managers have special behavior:
kml.points.all()collects from standalone Points AND Points within Placemarkskml.points.filter()only filters standalone Points at root levelSame applies for
pathsandpolygons
Common Pitfalls
Assuming
filter()searches nested elements - It doesn’t!Using
get()without.all()for nested elements - Will raiseKMLElementNotFoundCounting with
.count()instead of.all().count()- Undercounts nested elementsForgetting that geometry managers need
.all()to include Placemark geometries
Summary Recommendation
Important
When in doubt, use .all() before query methods. Most real-world KML files
organize elements in folders, so you’ll almost always want:
kml.placemarks.all().filter(...) # Not just kml.placemarks.filter(...)
folder.points.all().filter(...) # Not just folder.points.filter(...)
This ensures you’re searching the entire element tree, not just the immediate children.