yesterdays-panoramax
A Django app that publishes a Yesterdays historical image archive to the Panoramax federation, by serving a Panoramax-compatible STAC API.
Drop it into an existing installation: one dependency, one line in
INSTALLED_APPS, one URL include, one migration. It adds no column to the
images tables and changes no existing behaviour.
pip install yesterdays-panoramax
What it does
Panoramax is not a push protocol. A central meta-catalogue
(api.panoramax.xyz) runs a harvester that crawls each registered
instance's STAC API on a schedule and copies the metadata into a shared,
searchable database. The pictures never move — they stay on the instance that
hosts them.
This package makes a Yesterdays instance one of those crawlable instances. Your georeferenced historical photographs become discoverable alongside the rest of the federation, and every item links back to its record on your site.
It maps:
| Yesterdays | Panoramax / STAC |
|---|---|
images.Collection |
STAC Collection ("sequence") |
images.Image |
STAC Item ("picture") |
latest Georeference.point |
item geometry |
Georeference.direction |
view:azimuth |
Georeference.confidence |
quality:horizontal_accuracy |
Image.edtf_date |
datetime + start_datetime/end_datetime |
display_permalink / thumbnail |
hd / sd / thumb assets |
Quick start
# settings.py
INSTALLED_APPS = [
...,
"yesterdays_panoramax",
]
PANORAMAX_ENABLED = True
# images.License names -> SPDX identifiers.
PANORAMAX_LICENSE_ALLOWLIST = {
"No known copyright restrictions": "CC0-1.0",
"CC BY-SA 4.0": "CC-BY-SA-4.0",
}
PANORAMAX_INSTANCE_NAME = "Yesterdays"
PANORAMAX_CONTACT_EMAIL = "you@example.org"
# Set once. Never change it. See docs/configuration.md.
PANORAMAX_UUID_NAMESPACE = "6f3d6b1a-6b0e-5a3f-9c8d-0f1c2a4b8e7d"
# urls.py -- the /api/ prefix is not optional, see below
urlpatterns = [
...,
path("api/", include("yesterdays_panoramax.urls", namespace="panoramax")),
]
manage.py migrate panoramax
manage.py panoramax_backfill
[!IMPORTANT] The harvester builds its requests as
{instance_url}/api/collectionswith the prefix hardcoded, so the app must be mounted at/api/. If your project already serves something there — Yesterdays serves its REST API at/api/v2/— include this app after those routes.
Publication is opt-in twice over: PANORAMAX_ENABLED, and a licence allowlist
that starts empty. An instance with the flag on and no allowlist publishes
nothing. That is deliberate — Panoramax's federation policy expects open
licensing, and only a human can say which of an archive's licences qualify.
Ruling on individual photographs
Licences and visibility flags cannot express a judgement about one particular picture — a portrait whose subject asked not to have it republished, a scan whose provenance turned out to be murky. So decisions can also be made per image:
from yesterdays_panoramax import api
api.exclude_image(image, reason="Depicted person objected", by=request.user)
Or, for archives whose rights are settled picture by picture rather than licence by licence, invert the default so nothing is published until it is approved:
PANORAMAX_IMAGE_POLICY = "opt-in"
An exclusion is absolute; an approval is not an override — an approved image still has to satisfy the licence, visibility, date and georeference rules. The feature is inert until used. See per-image control.
Joining the federation
Serving the API is only half of it. To actually be harvested, open an issue on
panoramax/server/meta-catalog
asking to be added; an administrator runs
stac-harvester add-instance <name> --url https://your.instance. There is no
self-service endpoint.
Before you do, two questions the code cannot answer for you:
- Licensing. The federation expects Licence Ouverte 2.0 or CC-BY-SA 4.0,
and
/api/configurationadvertises one instance-wide licence. - Fit. Panoramax catalogues contemporary field photography for OpenStreetMap mapping. Historical photographs with crowd-estimated positions are a different kind of data. There is precedent — the OSM-FR instance carries items back to 1904 — but it is worth raising with the Panoramax community before publishing at scale.
Documentation
| Installation | Adding it to a Yesterdays project |
| Configuration | Every setting, and what it does |
| How it works | The federation model and the harvester contract |
| Data mapping | What gets published, and the judgement calls |
| Per-image control | Holding back, or approving, one photograph |
| Endpoints | The API surface |
| Operations | Backfilling, withdrawal, troubleshooting |
| Host contract | What the package needs from images |
| Releasing | Cutting a version |
Requirements
- Python 3.11+
- Django 4.2+
- PostgreSQL with PostGIS (the adapter aggregates extents, filters spatially,
and builds vector tiles with
ST_AsMVT) - A Yesterdays installation providing the
imagesapp — see host contract
Development
pip install -e ".[test]"
./manage.py test tests
The suite runs against a stubbed host app in tests/images/, so you do not
need a full Yesterdays deployment. It needs a PostGIS database; connection
details come from the usual PG* environment variables.
Licence
AGPL-3.0-or-later, matching Yesterdays. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yesterdays_panoramax-0.1.0.tar.gz.
File metadata
- Download URL: yesterdays_panoramax-0.1.0.tar.gz
- Upload date:
- Size: 72.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99ef97ee0deb9a00da171e9626326957b4df7fc43bacfcb5b1cc09aace82a1f0
|
|
| MD5 |
f7baa2422534f75069045985d73b4a17
|
|
| BLAKE2b-256 |
546e32a9adb8a12fe63041f1148228d3ac9dce74c9812aea23f4d14908c2bb01
|
Provenance
The following attestation bundles were made for yesterdays_panoramax-0.1.0.tar.gz:
Publisher:
publish.yml on openhistorymap/yesterdays-panoramax
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yesterdays_panoramax-0.1.0.tar.gz -
Subject digest:
99ef97ee0deb9a00da171e9626326957b4df7fc43bacfcb5b1cc09aace82a1f0 - Sigstore transparency entry: 2661176072
- Sigstore integration time:
-
Permalink:
openhistorymap/yesterdays-panoramax@419a9776ea24cb2ab9f1a50504b9c943128ff8ba -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/openhistorymap
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@419a9776ea24cb2ab9f1a50504b9c943128ff8ba -
Trigger Event:
release
-
Statement type:
File details
Details for the file yesterdays_panoramax-0.1.0-py3-none-any.whl.
File metadata
- Download URL: yesterdays_panoramax-0.1.0-py3-none-any.whl
- Upload date:
- Size: 58.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d22e9ab1aa80bf0daadc528ebf80e322dabe369d88841a79de1b55bebfc2f4d
|
|
| MD5 |
7cb0f5eb9848086177aa5f1c4cb87774
|
|
| BLAKE2b-256 |
ecbcfff5dc96658a61fc28a214f48a370df0b5fa98bfa7e683de9f2841bfdb4f
|
Provenance
The following attestation bundles were made for yesterdays_panoramax-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on openhistorymap/yesterdays-panoramax
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yesterdays_panoramax-0.1.0-py3-none-any.whl -
Subject digest:
3d22e9ab1aa80bf0daadc528ebf80e322dabe369d88841a79de1b55bebfc2f4d - Sigstore transparency entry: 2661176139
- Sigstore integration time:
-
Permalink:
openhistorymap/yesterdays-panoramax@419a9776ea24cb2ab9f1a50504b9c943128ff8ba -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/openhistorymap
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@419a9776ea24cb2ab9f1a50504b9c943128ff8ba -
Trigger Event:
release
-
Statement type: