Warehouse Pick Lists
Warehouse pick-list REST API: units, pick zones, waves and tote labels as incremental computed columns over Json order lines
One app.py with 1 table, 5 computed columns, 6 HTTP routes. Needs pixeltable[serve]>=0.7.15. Updated 2026-10-08.
app.py
"""Warehouse Pick-List API built with Pixeltable.Orders arrive with a Json list of lines. Total units, pick zones, estimated pick time, pick wave and thetote label are computed columns (Python UDFs in udfs.py) that Pixeltable keeps up to date on every insertand update. A FastAPIRouter serves insert / update / delete routes plus index-backed queries for thepick floor (open orders in a wave, one order's tote label).Layout: UDFs live in udfs.py (imported below); this file holds the tables, the @pxt.query functions and the routes.Run locally:pxt schema update app.py pickingpxt service run app.py pickingSee README.md for the walkthrough and Pixeltable Cloud deployment."""import pixeltable as pxtfrom pixeltable.serving import FastAPIRouterfrom udfs import label_text, pick_minutes, total_units, wave, zones# ---- tables ----TableModel = pxt.model_base()class Orders(TableModel, name='orders', has_default_idxs=False):order_id = pxt.Column(type=pxt.String, primary_key=True)customer: pxt.Stringlines: pxt.Jsonrush: pxt.Bool | Nonestatus: pxt.String # open -> picking -> packed -> shippednotes: pxt.Json | None# computed columns: chained UDFs, recomputed when an input column changesunits = total_units(lines)zone_list = zones(lines)est_minutes = pick_minutes(units, zone_list, rush)wave_name = wave(zone_list, rush)tote_label = label_text(order_id, wave_name, zone_list)__indexes__ = [pxt.BtreeIndex(status), pxt.BtreeIndex(wave_name), pxt.BtreeIndex(customer)]# ---- queries ----@pxt.querydef wave_queue(wave_name: str, status: str):"""Orders in a pick wave with a given status, longest pick first (index-backed)."""return (Orders.where((Orders.wave_name == wave_name) & (Orders.status == status)).select(Orders.order_id, Orders.customer, Orders.units, Orders.est_minutes, Orders.tote_label).order_by(Orders.est_minutes, asc=False))@pxt.querydef order_label(order_id: str):"""One order's tote label and pick estimate (0 rows -> 404)."""return Orders.where(Orders.order_id == order_id).select(Orders.order_id, Orders.tote_label, Orders.est_minutes, Orders.status)@pxt.querydef customer_orders(customer: str):"""A customer's orders, newest id first."""return (Orders.where(Orders.customer == customer).select(Orders.order_id, Orders.status, Orders.units, Orders.wave_name).order_by(Orders.order_id, asc=False))# ---- routes ----picking_api = FastAPIRouter(name='picking_api')picking_api.add_insert_route(Orders,path='/orders',inputs=[Orders.order_id, Orders.customer, Orders.lines, Orders.rush, Orders.status, Orders.notes],outputs=[Orders.order_id, Orders.units, Orders.zone_list, Orders.est_minutes, Orders.wave_name, Orders.tote_label],)picking_api.add_update_route(Orders,path='/orders/update',inputs=[Orders.status, Orders.lines, Orders.rush],outputs=[Orders.order_id, Orders.status, Orders.units, Orders.wave_name, Orders.est_minutes],)picking_api.add_delete_route(Orders, path='/orders/cancel')picking_api.add_query_route(path='/waves/queue', query=wave_queue, method='get')picking_api.add_query_route(path='/orders/label', query=order_label, one_row=True, method='get')picking_api.add_query_route(path='/customers/orders', query=customer_orders, method='get')
What app.py declares
Each row links to its line.
- runs on insert
- stored
- index
- route
- order_idcustomerlinesrushstatusnotes
- units = total_units(lines)L34
- zone_list = zones(lines)L35
- est_minutes = pick_minutes(units, zone_list, rush)L36
- wave_name = wave(zone_list, rush)L37
- tote_label = label_text(order_id, wave_name, zone_list)L38
- B-tree index on statusL40
- B-tree index on wave_nameL40
- B-tree index on customerL40
serves picking_api
- POST/ordersinsert, orderstakes order_id, customer, lines, rush, status, notes; returns order_id, units, zone_list, est_minutes, wave_name, tote_labelL75
- POST/orders/updateupdate, orderstakes status, lines, rush; returns order_id, status, units, wave_name, est_minutesL81
- POST/orders/canceldelete, ordersL87
- GET/waves/queuequery, wave_queuetakes wave_name, statusL88
- GET/orders/labelquery, order_labeltakes order_idL89
- GET/customers/ordersquery, customer_orderstakes customerL90
Run it
Needs uv. The routes then answer on port 8000.
terminal
git clone https://github.com/pierrebrunelle/pixeltable-warehouse-picklistscd pixeltable-warehouse-picklistsuv syncuv run pxt schema update app.py pickinguv run python seed.py pickinguv run pxt service run app.py picking --port 8000
Related apps
- Forge Heat CyclesForge heat-cycle registry API: B-tree indexes, chained risk UDFs, and parallel shop-floor writersShares: B-tree indexes, UDFs
- Climbing Route ToposClimbing-route topo registry API: photo uploads with thumbnails, grayscale copies, grade bands and index-backed crag lookupsShares: B-tree indexes, UDFs
- Ferry BookingFerry booking REST API: fares and deck classes as incremental computed columns, served with FastAPIShares: B-tree indexes, UDFs