Skip to content

[IA-5441] POC- orgunit v3 - #3306

Open
mestachs wants to merge 11 commits into
developfrom
poc/mestachs-orgunit-v3
Open

mestachs wants to merge 11 commits into
developfrom
poc/mestachs-orgunit-v3

Conversation

@mestachs

@mestachs mestachs commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

What problem is this PR solving?

proposition for a new orgunit api

Related JIRA tickets

IA-XXX, WC2-XXX, POLIO-XXX, POLIOPM-XXX SLEEP-XXX, SNT-XXX, CONSOLE-XXX

Changes

mainly addition (new v3 name space)

main changes

  • fields= DSL + schema endpoint,
  • fixed-shape vs sub-selectable relation fields,
  • ancestor_id ltree descendants,
  • bbox/within/outside spatial filters,
    • find descendants outside the shape of a country/region : /api/v3/orgunits/?ancestor_id=<country_id>&location__outside_org_unit=<country_id>&fields=id,name,latitude,longitude,ancestors(id,name)
    • find point outside a bbox : /api/v3/orgunits?location__outside_bbox=-8.60,4.19,-2.49,10.74&fields=id,name,latitude,longitude,ancestors(id,name)
  • strict param validation with suggestions,
  • explicit django-filter FilterSet
  • non-counting pagination (speed up queries)
  • a generic cross-endpoint nomenclature contract test (test_filter_nomenclature.py).

How to test

Explain how to test your PR.

If a specific config is required explain it here: dataset, account, profile, etc.

Print screen / video

Upload here print screens or videos showing the changes.

Notes

in the things I noticed we don't have indexes for search by name.

  • since most query are icontains : probably need a trigram based indexe to stay performant
  • ideally should be doubled by unaccent

Doc

Tell us where the doc can be found (docs folder, wiki, in the code...).

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

⚠️ [WARN] Ticket code in PR title (Poc/mestachs orgunit v3) not found.
Tried unsuccessfully to parse from branch (poc/mestachs-orgunit-v3).
Image will not be tagged with a ticket code (slug).

Comment thread iaso/api/v3/common/spatial_filters.py Fixed
Comment thread iaso/api/v3/org_units/views.py Fixed
Comment thread iaso/api/v3/org_units/views.py Fixed
@mestachs mestachs changed the title Poc/mestachs orgunit v3 POC- orgunit v3 Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

⚠️ [WARN] Ticket code in PR title (POC- orgunit v3) not found.
Tried unsuccessfully to parse from branch (poc/mestachs-orgunit-v3).
Image will not be tagged with a ticket code (slug).

@github-actions

Copy link
Copy Markdown

⚠️ [WARN] Ticket code in PR title (POC- orgunit v3) not found.
Tried unsuccessfully to parse from branch (poc/mestachs-orgunit-v3).
Image will not be tagged with a ticket code (slug).

@github-actions

Copy link
Copy Markdown

⚠️ [WARN] Ticket code in PR title (POC- orgunit v3) not found.
Tried unsuccessfully to parse from branch (poc/mestachs-orgunit-v3).
Image will not be tagged with a ticket code (slug).

@github-actions

Copy link
Copy Markdown

⚠️ [WARN] Ticket code in PR title (POC- orgunit v3) not found.
Tried unsuccessfully to parse from branch (poc/mestachs-orgunit-v3).
Image will not be tagged with a ticket code (slug).

Comment thread iaso/api/v3/common/errors.py Fixed
@github-actions

Copy link
Copy Markdown

⚠️ [WARN] Ticket code in PR title (POC- orgunit v3) not found.
Tried unsuccessfully to parse from branch (poc/mestachs-orgunit-v3).
Image will not be tagged with a ticket code (slug).

@mestachs
mestachs marked this pull request as ready for review September 17, 2026 14:34
@github-actions

Copy link
Copy Markdown

⚠️ [WARN] Ticket code in PR title (POC- orgunit v3) not found.
Tried unsuccessfully to parse from branch (poc/mestachs-orgunit-v3).
Image will not be tagged with a ticket code (slug).

@github-actions

Copy link
Copy Markdown

⚠️ [WARN] Ticket code in PR title (POC- orgunit v3) not found.
Tried unsuccessfully to parse from branch (poc/mestachs-orgunit-v3).
Image will not be tagged with a ticket code (slug).

@mestachs

mestachs commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor Author

nice tool to test the api "validations"

TOKEN=$(curl -s -X POST http://localhost:8081/api/token/ \
  -H "Content-Type: application/json" \
  -d '{"username":"testemailstable-2-40-12","password":"testemailstable-2-40-12"}' \
  | jq -r .access)

uvx schemathesis run \
  "http://localhost:8081/swagger/?format=json" \
  --header "Authorization: Bearer $TOKEN" \
  --include-path-regex '^/api/v3/orgunits' \
  -c not_a_server_error \
  -n 300 \
  --report json,junit \
  --report-dir ./schemathesis-report

@tdethier tdethier left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

general comments in any order:

  • this is a great starting point, thanks for the huge work 👍
  • i like that the API is aware of all valid params and can refuse unknown ones instead of ignoring them
  • i like that the API can suggest valid options in case of spelling mistakes for instance
  • i don't like that adding a new field somewhere is much harder - the same field has to be added in:
    • a serializer (which is ok)
    • the whist list of fields (would it be possible to not make them and generate the white list based off serializer attributes instead?)
    • in batch_xxx methods to actually fetch data
    • in batch_xxx_for_queryset methods to fetch data for exports
    • in only_columns_for_field_tree (i'm not sure why)
    • maybe in other places as well? this sounds very complicated to maintain
  • i don't like how csv/xlsx exports are handled: most of the code is more or less duplicated, it's gonna be really hard to maintain + it reuses the same old "get_row" logic with inner functions like old endpoints
  • we should have more tests
  • the API test file (test_org_units.py) should be split in test_views/filters/pagination/... like we usually do
  • i didn't check if there were features/fields/... that exist in the current API but are missing in this new version
  • we should handle the security alerts that github raised, they make sense
  • we should get inputs from other team members and decide on how we go from there - personally, i like the added features, but i think the maintenance cost is too high compared to their added value (at least in the current version); getting rid of some new features, or implementing them differently might be better? i'm not sure

@@ -0,0 +1,99 @@
"""Parser for the v3 `fields=` query parameter sub-selector grammar.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should add unit tests for all helpers in this file

CORE_EXTRA_ALLOWED_PARAMS: FrozenSet[str] = frozenset({"order", "format", "page", "page_size", "with_count", "fields"})


class BaseV3FilterSet(django_filters.FilterSet):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would also add unit tests to check the behavior of this class, with filters that inherit from it and define extra_allowed_params or not

Comment thread iaso/api/v3/common/param_validator.py
return # To not perform the csrf check previously happening


class CsrfExemptSessionAuthenticationScheme(OpenApiAuthenticationExtension):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why we have this, was it needed for swagger?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's to be able to test the schema generation :
iaso/tests/api/v3/test_openapi_schema.py::V3SchemaDocumentationTestCase::test_v3_endpoints_generate_a_clean_openapi_schema

Comment thread iaso/api/v3/common/spatial_filters.py Outdated
def __init__(self, *args, geometry_field: str, org_unit_model, **kwargs):
super().__init__(*args, **kwargs)
self.geometry_field = geometry_field
self.org_unit_model = org_unit_model

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why you need to pass the OrgUnit model here, if you're checking geom and simplified_geom, you already know that it's this model and you don't need to pass it? otherwise it sounds like we have multiple models that store geo data, with the same attribute names, but i don't think we do

Comment thread iaso/tests/api/v3/test_org_units.py Outdated
Comment on lines +704 to +706
self.assertEqual(row["name"], "Theed District")
self.assertEqual(row["ancestors[0].name"], "Naboo") # root
self.assertEqual(row["ancestors[1].name"], "Theed") # immediate parent

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here as well, i would assert with values from OrgUnit objects from the setup instead of hardcoding values with comments

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be honest I fixed it but I don't like that... it finally feels your "test" is too smart and don't detect anything (like playing with mock, and you don't even realize that you test your mock and not the implementation)

Comment thread iaso/tests/api/v3/test_org_units.py Outdated
self.assertIn("parqet", data["error"])
self.assertIn("parquet", data["detail"])

def test_format_csv(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for all csv tests: there's a self.assertCsvFileResponse() utility you can use

Comment thread iaso/tests/api/v3/test_org_units.py Outdated
content = b"".join(response.streaming_content).decode("utf-8")
self.assertIn("Theed", content)

def test_format_xlsx(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and for all xlsx tests, there's a self.assertXlsxFileResponse() utility you can use

Comment thread iaso/tests/api/v3/test_org_units.py Outdated
Comment on lines +857 to +862
main_query = next(
q["sql"] for q in ctx.captured_queries if q["sql"].strip().startswith('SELECT "iaso_orgunit".')
)
# `LEFT OUTER JOIN` is what `select_related` would add; the account-scoping subquery
# (`filter_for_account`) legitimately uses `INNER JOIN` in its own nested SELECT, which is fine.
self.assertNotIn("LEFT OUTER JOIN", main_query)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure that the first query with 'SELECT "iaso_orgunit".' will be the right one? are they always in the right order? can't there be another query on this table before the "big" query with select/prefetch related?

Comment thread iaso/tests/api/v3/test_org_units.py Outdated
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assert_parquet_content_type(response)
with open("/tmp/v3_orgunits_test.parquet", "wb") as f:
write_response_to_file(response, f)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no assert after writing the file? what's the point of writing the file then?

@tdethier tdethier changed the title POC- orgunit v3 [IA-5441] POC- orgunit v3 Sep 22, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants