Reputation: 11935
I have two models:
Model_A that contains a GeoDjango Point;
Model_B that contains a GeoDjnago MultiPololygon;
For every element in Model_A I have to check if the point is contained into some m_polygon of Model_B element;
I'm able to make this simple query.
But I also thought: I have a lot of elements in Model_A and few elements in Model_B. So, probably is more efficient to iterate all elements in Model_B and check if exist some element in Model_A that it is contained into the current Model_B element.
So, is there any way to make this GeoDjango query?
Something like this:
Model_A.objects.filter(*point_is_contained_into*=a_model_b_mpolygon);
------------------ EDIT -----------------
I tried to use this:
result = Model_A.objects.filter(position__intersects=a_model_b_mpolygon)
And this works for me. Are there contraindications to use this type of query in my case?
Upvotes: 4
Views: 1988
Reputation: 23134
From Django version 1.11 you have an optimized option to solve this query.
Assumptions:
Model_A
has a geometry field called: model_a_point
.Model_B
has a geometry field called: model_b_poly
.Methods used:
Subquery()
, new method in Django 1.11 which allows the definition of queries with a subquery part.
OuterRef()
, new method in Django 1.11 which is used:
when a queryset in a Subquery needs to refer to a field from the outer query.
within()
, which:
Tests if the geometry field is spatially within the lookup geometry.
annotate()
, which will generate for each item in a queryset, a new field (in our case it will contain the points contained by a polygon.)
Query:
Model_B.objects.annotate(
contained_points=Subquery(
Model_A.objects.filter(
model_a_point__within=OuterRef('model_b_poly')
) # Ref: 1, referenced below, keep reading
)
)
Result and something more:
The query above will have a field contained_points
for every polygon in Model_B
which contains every point from Model_A
contained by this polygon.
If you only want to keep geometry field of those points (lon, lan
), at the end of the Subquery
call (Ref: 1), use the values()
method.
Upvotes: 3