Skip to content

Django API Reference

yoromaps.django

Django integration package. Add "yoromaps.django" to INSTALLED_APPS.

yoromaps.django

Yoro Maps Django integration.

Add to your settings::

import yoromaps

INSTALLED_APPS = [..., "yoromaps.django"]

DATABASES = {
    "default": { ... },
    "maps": yoromaps.db_config("/path/to/country.yoromaps"),
}

yoromaps.django.views

Django views for tile serving and routing.

yoromaps.django.views

Django views for yoro-maps — tile serving, routing, and POI API.

tile_view(request, z, x, y)

Serve a map tile from the .yoromaps database.

GET /maps/tiles/{z}/{x}/{y}.png

Source code in src/yoromaps/django/views.py
@require_GET
def tile_view(request: HttpRequest, z: int, x: int, y: int) -> HttpResponse:
    """Serve a map tile from the .yoromaps database.

    ``GET /maps/tiles/{z}/{x}/{y}.png``
    """
    db_path = _get_maps_db()
    if not db_path:
        return HttpResponse(status=404)

    conn = _get_conn(db_path)
    data = get_tile(conn, int(z), int(x), int(y))

    if data:
        resp = HttpResponse(data, content_type="image/png")
        resp["Cache-Control"] = "public, max-age=86400"
        return resp
    return HttpResponse(status=404)

route_view(request)

Calculate a route between Yoro codes.

GET /maps/route/?codes=ML-ABC,ML-XYZ

Source code in src/yoromaps/django/views.py
@require_GET
def route_view(request: HttpRequest) -> JsonResponse:
    """Calculate a route between Yoro codes.

    ``GET /maps/route/?codes=ML-ABC,ML-XYZ``
    """
    codes_str = request.GET.get("codes", "")
    codes = [c.strip() for c in codes_str.split(",") if c.strip()]

    if len(codes) < 2:
        return JsonResponse({"error": "At least 2 Yoro codes required"}, status=400)

    db_path = _get_maps_db()
    if not db_path:
        return JsonResponse({"error": "Maps database not configured"}, status=500)

    # The graph is loaded once per process and reused across requests
    # (invalidated when the .yoromaps file changes on disk).
    try:
        graph = get_graph(db_path)
    except FileNotFoundError:
        return JsonResponse({"error": f"Maps database not found: {db_path}"}, status=500)

    try:
        legs = route_from_codes(_get_conn(db_path), codes, graph=graph)
    except ValueError as e:
        return JsonResponse({"error": str(e)}, status=400)

    total_km = sum(leg.distance_km for leg in legs)
    total_min = sum(leg.duration_min for leg in legs)

    return JsonResponse(
        {
            "total_distance_km": total_km,
            "total_duration_min": total_min,
            "found": all(leg.found for leg in legs),
            "legs": [
                {
                    "distance_km": leg.distance_km,
                    "duration_min": leg.duration_min,
                    "found": leg.found,
                    "geometry": leg.geometry,
                    "steps": leg.steps,
                }
                for leg in legs
            ],
        }
    )

pois_view(request)

Query points of interest.

GET /maps/pois/?cell=CI-4H7A3B — POIs inside a Yoro cell GET /maps/pois/?lat=6.8&lon=-5.3&radius=2000 — POIs within a radius (m) GET /maps/pois/?q=marche&category=market — search by name/category

Source code in src/yoromaps/django/views.py
@require_GET
def pois_view(request: HttpRequest) -> JsonResponse:
    """Query points of interest.

    ``GET /maps/pois/?cell=CI-4H7A3B`` — POIs inside a Yoro cell
    ``GET /maps/pois/?lat=6.8&lon=-5.3&radius=2000`` — POIs within a radius (m)
    ``GET /maps/pois/?q=marche&category=market`` — search by name/category
    """
    from yoromaps.poi import pois_in_cell, pois_near, search_pois

    db_path = _get_maps_db()
    if not db_path:
        return JsonResponse({"error": "Maps database not configured"}, status=500)

    conn = _get_conn(db_path)
    category = request.GET.get("category") or None

    try:
        if request.GET.get("cell"):
            pois = pois_in_cell(conn, request.GET["cell"], category=category)
        elif request.GET.get("lat") and request.GET.get("lon"):
            lat = float(request.GET["lat"])
            lon = float(request.GET["lon"])
            radius = float(request.GET.get("radius", 1000))
            pois = pois_near(conn, lat, lon, radius_m=radius, category=category)
        else:
            pois = search_pois(conn, query=request.GET.get("q"), category=category)
    except ValueError as e:
        return JsonResponse({"error": str(e)}, status=400)

    return JsonResponse({"count": len(pois), "pois": pois})

close_connection()

Close this thread's cached read connection, if it holds one.

A server keeps the connection for the life of the thread on purpose — not reopening SQLite on every request is the whole point of the cache. Anything shorter-lived than a server, a test or a management command or a worker winding down, should call this: otherwise the connection is only released when the interpreter collects it, which Python 3.13 reports as an unclosed database rather than ignoring.

Source code in src/yoromaps/django/views.py
def close_connection() -> None:
    """Close this thread's cached read connection, if it holds one.

    A server keeps the connection for the life of the thread on purpose —
    not reopening SQLite on every request is the whole point of the cache.
    Anything shorter-lived than a server, a test or a management command or a
    worker winding down, should call this: otherwise the connection is only
    released when the interpreter collects it, which Python 3.13 reports as an
    unclosed database rather than ignoring.
    """
    conn = getattr(_local, "conn", None)
    if conn is None:
        return
    conn.close()
    _local.conn = None
    _local.db_path = None

yoromaps.django.urls

URL configuration. Include with:

path("maps/", include("yoromaps.django.urls"))

Registered URL patterns

Pattern Name View
tiles/<int:z>/<int:x>/<int:y>.png tile tile_view
route/ route route_view

yoromaps.django.apps

yoromaps.django.apps

YoroMapsConfig

Bases: AppConfig

Source code in src/yoromaps/django/apps.py
4
5
6
7
8
class YoroMapsConfig(AppConfig):
    name = "yoromaps.django"
    label = "yoromaps"
    verbose_name = "Yoro Maps"
    default_auto_field = "django.db.models.BigAutoField"