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
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.
Metadata
Release files for yesterdays-panoramax 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| yesterdays_panoramax-0.1.0.tar.gz | 72.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yesterdays_panoramax-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 131.1 kB
Release files / yesterdays_panoramax-0.1.0.tar.gz
| Download URL | yesterdays_panoramax-0.1.0.tar.gz |
|---|---|
| Size | 72.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
99ef97ee0deb9a00da171e9626326957b4df7fc43bacfcb5b1cc09aace82a1f0
|
|
BLAKE2b-256 checksum How to use checksums |
546e32a9adb8a12fe63041f1148228d3ac9dce74c9812aea23f4d14908c2bb01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency logRelease files / yesterdays_panoramax-0.1.0-py3-none-any.whl
| Download URL | yesterdays_panoramax-0.1.0-py3-none-any.whl |
|---|---|
| Size | 58.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3d22e9ab1aa80bf0daadc528ebf80e322dabe369d88841a79de1b55bebfc2f4d
|
|
BLAKE2b-256 checksum How to use checksums |
ecbcfff5dc96658a61fc28a214f48a370df0b5fa98bfa7e683de9f2841bfdb4f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency logSecurity for yesterdays-panoramax 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for yesterdays_panoramax-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.