Skip to main content

catalogue-server

catalogue-server is a Django app for a central book catalogue that other sites read. It owns works, editions, country-specific prices, distributors, public catalogue pages, and the read-only JSON API documented in API.md.

Use it when one catalogue needs to describe the same work in several editions and languages, show different availability by visitor country, and publish the same structured data to other websites. The package contains no catalogue content and makes no assumptions about a particular author, publisher, shop, or country.

The central model is a Work (the intellectual title), containing one or more Book editions. A book can have country-specific details and offers from distributors or other shops. Distributors may be maintained by hand or updated from supported shop platforms.

Quick start

Install the core package, or select extras for the integrations you use:

pip install catalogue-server
pip install "catalogue-server[geoip,shops,servicetrees]"

Add catalogue_server.apps.CatalogueServerConfig to INSTALLED_APPS, then include both URL modules:

path("api/v1/", include("catalogue_server.api_urls")),
path("books/", include("catalogue_server.urls")),

Run migrations, then create works, books, distributors, and offers through Django admin or your project's own editor:

python manage.py migrate
python manage.py runserver

The public catalogue is now under /books/, and the read-only API is under /api/v1/. See API.md for endpoints and response formats.

The Django app label remains catalogue, so an existing installation can change its Python import path without renaming database tables or migration dependencies. servicetrees is an optional extra (catalogue-server[servicetrees]) because a book can link to a display page. The image fields do not need it.

Optional settings:

  • GEOIP_COUNTRY_DB: path to a GeoLite2 Country database.
  • CATALOGUE_DEFAULT_COUNTRY: fallback ISO country code.
  • CATALOGUE_API_CACHE_SECONDS: public API cache lifetime (default 3600).
  • CATALOGUE_SHOP_PARSERS: extra shop parsers, {'key': 'dotted.path.to.parse'}.
  • CATALOGUE_AUTHOR: for a single-author catalogue, new books' default author, used in page titles ("Books by …") and by shop scans to keep unmatched products by that author.
  • CATALOGUE_NAME: the catalogue's name in page titles (when the site has no site_name).
  • CATALOGUE_SHOP_USER_AGENT: User-Agent for shop scans (name your site and a contact URL).

Signals keep scanned offers matched: adding or deleting a book, or changing what matching uses (title, subtitle, ISBN, language, format, author), matches the stored shop products again without asking the shops. shops.scan.scan_in_background(distributor) reads one shop in a thread, for a site's editor to call when a distributor's shop settings change.

Shops and offers

An Offer is one shop selling a book: a link, and when known a price, currency and stock. A book page shows the best offer for the visitor's country as the main button (in stock, a distributor before other shops, surest match, cheapest) and every other shop in a side panel.

Offers come from two places:

  • Scanned: python manage.py scan_shops (daily cron) reads each published distributor's online shop with its shop_parser and shop_options, matches the products to books (ISBN, else title: see shops/scan.py) and keeps one offer per product URL. Products naming one of the catalogue's authors that match no book (or all products, with the keep_unmatched option) are kept without a book: filter offers by "Book: none" and pick the book (scans keep that choice). Built-in parsers read WooCommerce's Store API, Shopify's products.json, Squarespace's ?format=json, and Wix Stores' public storefront API. A site adds its own with CATALOGUE_SHOP_PARSERS (parse(options, session) yielding shops.ShopProduct). Needs the shops extra.
  • By hand: for shops without a parser, or that are not distributors (marketplaces and app stores), on the book's admin page: a shop name and countries instead of a distributor. Without countries such a shop counts as selling everywhere.

Each distributor has a public page (/books/distributors/<slug>/) with the books it sells and their prices.

A distributor's ships_to lists every country it delivers to. When it is known it decides where its offers count as available; when empty only its own countries do. Parsers that can read it (Shopify meta.json, or a site's own parsers) fill it on each scan unless ships_to_locked; for the others enter it from the shop's delivery terms and lock it. WooCommerce's cart-page country list is not used: it mixes selling and shipping countries and leaves out countries without state data. When no shop delivers to the visitor's country, the purchase box still shows the best shop, with a warning.

Built-in shop parser options

Every parser needs url, the shop's base URL. The remaining JSON options are platform-specific:

Parser Options
woocommerce category: optional category slug or id
shopify category: optional collection handle; currency: currency code when the feed omits it
squarespace path: store page path, default /shop
wix path: store page path, default /shop; categories: names to include; currency: fallback currency

Wix can also set language metadata without baking one shop into the package: category_languages maps a category name or a word in it to an ISO language code, and default_language supplies the fallback. For example:

{
  "url": "https://shop.example",
  "path": "/books",
  "categories": ["Books EN", "Books DE"],
  "category_languages": {"EN": "en", "DE": "de"}
}

Keep publisher-, author-, or site-specific cleanup in the host project. Register a small wrapper with CATALOGUE_SHOP_PARSERS; it can call a built-in parser and adjust the yielded ShopProduct objects. This keeps the package useful to unrelated catalogues.

The purchase box also links the book's editions in other languages ("Czech language edition / Vydání v češtině: …"), those sold in the visitor's country first. The phrases in each language are countries.NATIVE_EDITION_LABELS.

Covers, extra images and distributor logos are image fields. They upload as normal files. When servicetrees mediaapp is installed it becomes the default file storage, so those uploads (and every other file field) are recorded in the media library. Linking a book to a display page still uses servicetrees displaypage.

The package holds no catalogue data: a site loads its own books and distributors (fixtures, a seed command, or the admin).

Development

For local development, install the checkout as an editable dependency:

pip install -e ./path/to/catalogue_server
python manage.py test catalogue_server

When testing an integration with servicetrees, install that checkout too or use the servicetrees extra. Templates and static files use Django's standard override rules, so a host project can provide its own catalogue design.

Vasudeva Server

Metadata

Release files for catalogue-server 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for catalogue-server 0.1.0
File Interpreter ABI Platform
catalogue_server-0.1.0-py3-none-any.whl Python 3 none any Details

Release files / catalogue_server-0.1.0-py3-none-any.whl

Download URL catalogue_server-0.1.0-py3-none-any.whl
Size 60.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
92f4af2c12ea89cf176c54d49e6aaacd89a23e8d9d326211218cf10dbe75b7e8
BLAKE2b-256 checksum
How to use checksums
0cf5c23a89d8bbee164d3ef3fe7fe995e8ffdf16ce5a57ef8d6aa2dc280906ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.11.17

Security for catalogue-server 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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page