Compare commits

..

5 commits

Author SHA1 Message Date
af2ea18e1d bump: version 0.7.0 → 0.8.0 2026-03-04 20:43:03 -06:00
23af35842d feat: improve support for exporting quantity, log data
and make the Eggs quick form save to wuttafarm app DB first, then
export to farmOS, if app is running as mirror
2026-03-04 20:36:56 -06:00
609a900f39 feat: show related Quantity records when viewing a Measure 2026-03-04 16:51:26 -06:00
a547188a90 feat: show related Quantity records when viewing a Unit 2026-03-04 16:49:28 -06:00
81fa22bbd8 feat: show link to Log record when viewing Quantity 2026-03-04 14:49:12 -06:00
12 changed files with 600 additions and 44 deletions

View file

@ -5,6 +5,19 @@ All notable changes to WuttaFarm will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## v0.8.0 (2026-03-04)
### Feat
- improve support for exporting quantity, log data
- show related Quantity records when viewing a Measure
- show related Quantity records when viewing a Unit
- show link to Log record when viewing Quantity
### Fix
- bump version requirement for wuttaweb
## v0.7.0 (2026-03-04)
### Feat

View file

@ -5,7 +5,7 @@ build-backend = "hatchling.build"
[project]
name = "WuttaFarm"
version = "0.7.0"
version = "0.8.0"
description = "Web app to integrate with and extend farmOS"
readme = "README.md"
authors = [

View file

@ -376,6 +376,7 @@ class LogQuantity(model.Base):
quantity = orm.relationship(
"Quantity",
foreign_keys=quantity_uuid,
back_populates="_log",
)

View file

@ -26,6 +26,7 @@ Model definition for Quantities
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.ext.associationproxy import association_proxy
from wuttjamaican.db import model
@ -161,6 +162,25 @@ class Quantity(model.Base):
""",
)
_log = orm.relationship(
"LogQuantity",
uselist=False,
cascade="all, delete-orphan",
cascade_backrefs=False,
back_populates="quantity",
)
def make_log_quantity(log):
from wuttafarm.db.model import LogQuantity
return LogQuantity(log=log)
log = association_proxy(
"_log",
"log",
creator=make_log_quantity,
)
def render_as_text(self, config=None):
measure = str(self.measure or self.measure_id or "")
value = self.value_numerator / self.value_denominator
@ -202,6 +222,7 @@ def add_quantity_proxies(subclass):
Quantity.make_proxy(subclass, "quantity", "units_uuid")
Quantity.make_proxy(subclass, "quantity", "units")
Quantity.make_proxy(subclass, "quantity", "label")
Quantity.make_proxy(subclass, "quantity", "log")
class StandardQuantity(QuantityMixin, model.Base):

View file

@ -443,6 +443,138 @@ class StructureAssetImporter(ToFarmOSAsset):
return payload
##############################
# quantity importers
##############################
class ToFarmOSQuantity(ToFarmOS):
"""
Base class for quantity data importer targeting the farmOS API.
"""
farmos_quantity_type = None
supported_fields = [
"uuid",
"measure",
"value_numerator",
"value_denominator",
"label",
"quantity_type_uuid",
"unit_uuid",
]
def get_target_objects(self, **kwargs):
return list(
self.farmos_client.resource.iterate("quantity", self.farmos_quantity_type)
)
def get_target_object(self, key):
# fetch from cache, if applicable
if self.caches_target:
return super().get_target_object(key)
# okay now must fetch via API
if self.get_keys() != ["uuid"]:
raise ValueError("must use uuid key for this to work")
uuid = key[0]
try:
qty = self.farmos_client.resource.get_id(
"quantity", self.farmos_quantity_type, str(uuid)
)
except requests.HTTPError as exc:
if exc.response.status_code == 404:
return None
raise
return qty["data"]
def create_target_object(self, key, source_data):
if source_data.get("__ignoreme__"):
return None
if self.dry_run:
return source_data
payload = self.get_quantity_payload(source_data)
result = self.farmos_client.resource.send(
"quantity", self.farmos_quantity_type, payload
)
normal = self.normalize_target_object(result["data"])
normal["_new_object"] = result["data"]
return normal
def update_target_object(self, quantity, source_data, target_data=None):
if self.dry_run:
return quantity
payload = self.get_quantity_payload(source_data)
payload["id"] = str(source_data["uuid"])
result = self.farmos_client.resource.send(
"quantity", self.farmos_quantity_type, payload
)
return self.normalize_target_object(result["data"])
def normalize_target_object(self, qty):
result = {
"uuid": UUID(qty["id"]),
"measure": qty["attributes"]["measure"],
"value_numerator": qty["attributes"]["value"]["numerator"],
"value_denominator": qty["attributes"]["value"]["denominator"],
"label": qty["attributes"]["label"],
"quantity_type_uuid": UUID(
qty["relationships"]["quantity_type"]["data"]["id"]
),
"unit_uuid": None,
}
if unit := qty["relationships"]["units"]["data"]:
result["unit_uuid"] = UUID(unit["id"])
return result
def get_quantity_payload(self, source_data):
attrs = {}
if "measure" in self.fields:
attrs["measure"] = source_data["measure"]
if "value_numerator" in self.fields and "value_denominator" in self.fields:
attrs["value"] = {
"numerator": source_data["value_numerator"],
"denominator": source_data["value_denominator"],
}
if "label" in self.fields:
attrs["label"] = source_data["label"]
rels = {}
if "quantity_type_uuid" in self.fields:
rels["quantity_type"] = {
"data": {
"id": str(source_data["quantity_type_uuid"]),
"type": "quantity_type--quantity_type",
}
}
if "unit_uuid" in self.fields:
rels["units"] = {
"data": {
"id": str(source_data["unit_uuid"]),
"type": "taxonomy_term--unit",
}
}
payload = {"attributes": attrs, "relationships": rels}
return payload
class StandardQuantityImporter(ToFarmOSQuantity):
model_title = "StandardQuantity"
farmos_quantity_type = "standard"
##############################
# log importers
##############################
@ -464,8 +596,14 @@ class ToFarmOSLog(ToFarmOS):
"status",
"notes",
"quick",
"assets",
"quantities",
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.normal = self.app.get_normalizer(self.farmos_client)
def get_target_objects(self, **kwargs):
result = self.farmos_client.log.get(self.farmos_log_type)
return result["data"]
@ -511,19 +649,18 @@ class ToFarmOSLog(ToFarmOS):
return self.normalize_target_object(result["data"])
def normalize_target_object(self, log):
if notes := log["attributes"]["notes"]:
notes = notes["value"]
normal = self.normal.normalize_farmos_log(log)
return {
"uuid": UUID(log["id"]),
"name": log["attributes"]["name"],
"timestamp": self.normalize_datetime(log["attributes"]["timestamp"]),
"is_movement": log["attributes"]["is_movement"],
"is_group_assignment": log["attributes"]["is_group_assignment"],
"status": log["attributes"]["status"],
"notes": notes,
"quick": log["attributes"]["quick"],
"uuid": UUID(normal["uuid"]),
"name": normal["name"],
"timestamp": self.app.make_utc(normal["timestamp"]),
"is_movement": normal["is_movement"],
"is_group_assignment": normal["is_group_assignment"],
"status": normal["status"],
"notes": normal["notes"],
"quick": normal["quick"],
"assets": [(a["asset_type"], UUID(a["uuid"])) for a in normal["assets"]],
"quantities": [UUID(uuid) for uuid in normal["quantity_uuids"]],
}
def get_log_payload(self, source_data):
@ -542,10 +679,32 @@ class ToFarmOSLog(ToFarmOS):
if "notes" in self.fields:
attrs["notes"] = {"value": source_data["notes"]}
if "quick" in self.fields:
attrs["quick"] = {"value": source_data["quick"]}
attrs["quick"] = source_data["quick"]
payload = {"attributes": attrs}
rels = {}
if "assets" in self.fields:
assets = []
for asset_type, uuid in source_data["assets"]:
assets.append(
{
"type": f"asset--{asset_type}",
"id": str(uuid),
}
)
rels["asset"] = {"data": assets}
if "quantities" in self.fields:
quantities = []
for uuid in source_data["quantities"]:
quantities.append(
{
# TODO: support other quantity types
"type": "quantity--standard",
"id": str(uuid),
}
)
rels["quantity"] = {"data": quantities}
payload = {"attributes": attrs, "relationships": rels}
return payload

View file

@ -104,6 +104,7 @@ class FromWuttaFarmToFarmOS(FromWuttaFarmHandler, ToFarmOSHandler):
importers["PlantType"] = PlantTypeImporter
importers["PlantAsset"] = PlantAssetImporter
importers["Unit"] = UnitImporter
importers["StandardQuantity"] = StandardQuantityImporter
importers["ActivityLog"] = ActivityLogImporter
importers["HarvestLog"] = HarvestLogImporter
importers["MedicalLog"] = MedicalLogImporter
@ -347,6 +348,49 @@ class StructureAssetImporter(
}
##############################
# quantity importers
##############################
class FromWuttaFarmQuantity(FromWuttaFarm):
"""
Base class for WuttaFarm -> farmOS quantity importers
"""
supported_fields = [
"uuid",
"measure",
"value_numerator",
"value_denominator",
"label",
"quantity_type_uuid",
"unit_uuid",
]
def normalize_source_object(self, qty):
return {
"uuid": qty.farmos_uuid or self.app.make_true_uuid(),
"measure": qty.measure_id,
"value_numerator": qty.value_numerator,
"value_denominator": qty.value_denominator,
"label": qty.label,
"quantity_type_uuid": qty.quantity_type.farmos_uuid,
"unit_uuid": qty.units.farmos_uuid,
"_src_object": qty,
}
class StandardQuantityImporter(
FromWuttaFarmQuantity, farmos_importing.model.StandardQuantityImporter
):
"""
WuttaFarm farmOS API exporter for Standard Quantities
"""
source_model_class = model.StandardQuantity
##############################
# log importers
##############################
@ -365,6 +409,9 @@ class FromWuttaFarmLog(FromWuttaFarm):
"is_group_assignment",
"status",
"notes",
"quick",
"assets",
"quantities",
]
def normalize_source_object(self, log):
@ -376,6 +423,9 @@ class FromWuttaFarmLog(FromWuttaFarm):
"is_group_assignment": log.is_group_assignment,
"status": log.status,
"notes": log.notes,
"quick": self.config.parse_list(log.quick) if log.quick else [],
"assets": [(a.asset_type, a.farmos_uuid) for a in log.assets],
"quantities": [qty.farmos_uuid for qty in log.quantities],
"_src_object": log,
}

View file

@ -77,6 +77,31 @@ class LogQuick(WuttaSet):
return LogQuickWidget(**kwargs)
class LogRef(ObjectRef):
"""
Custom schema type for a
:class:`~wuttafarm.db.model.log.Log` reference field.
This is a subclass of
:class:`~wuttaweb:wuttaweb.forms.schema.ObjectRef`.
"""
@property
def model_class(self): # pylint: disable=empty-docstring
""" """
model = self.app.model
return model.Log
def sort_query(self, query): # pylint: disable=empty-docstring
""" """
return query.order_by(self.model_class.message)
def get_object_url(self, obj): # pylint: disable=empty-docstring
""" """
log = obj
return self.request.route_url(f"logs_{log.log_type}.view", uuid=log.uuid)
class FarmOSUnitRef(colander.SchemaType):
def serialize(self, node, appstruct):

View file

@ -32,6 +32,7 @@ from wuttaweb.forms.widgets import WuttaDateTimeWidget
from wuttafarm.web.views.farmos import FarmOSMasterView
from wuttafarm.web.forms.schema import FarmOSUnitRef
from wuttafarm.web.grids import ResourceData
class QuantityTypeView(FarmOSMasterView):
@ -130,13 +131,15 @@ class QuantityMasterView(FarmOSMasterView):
farmos_quantity_type = None
grid_columns = [
"drupal_id",
"as_text",
"measure",
"value",
"unit",
"label",
"changed",
]
sort_defaults = ("changed", "desc")
sort_defaults = ("drupal_id", "desc")
form_fields = [
"measure",
@ -147,20 +150,58 @@ class QuantityMasterView(FarmOSMasterView):
"changed",
]
def get_grid_data(self, columns=None, session=None):
result = self.farmos_client.resource.get("quantity", self.farmos_quantity_type)
return [self.normalize_quantity(t) for t in result["data"]]
def get_farmos_api_includes(self):
return {"units"}
def get_grid_data(self, **kwargs):
return ResourceData(
self.config,
self.farmos_client,
f"quantity--{self.farmos_quantity_type}",
include=",".join(self.get_farmos_api_includes()),
normalizer=self.normalize_quantity,
)
def configure_grid(self, grid):
g = grid
super().configure_grid(g)
# drupal_id
g.set_label("drupal_id", "ID", column_only=True)
# as_text
g.set_renderer("as_text", self.render_as_text_for_grid)
# measure
g.set_renderer("measure", self.render_measure_for_grid)
# value
g.set_link("value")
g.set_renderer("value", self.render_value_for_grid)
# unit
g.set_renderer("unit", self.render_unit_for_grid)
# changed
g.set_renderer("changed", "datetime")
def render_as_text_for_grid(self, qty, field, value):
measure = qty["measure"].capitalize()
value = qty["value"]["decimal"]
units = qty["unit"]["name"] if qty["unit"] else "??"
return f"( {measure} ) {value} {units}"
def render_measure_for_grid(self, qty, field, value):
return qty["measure"].capitalize()
def render_unit_for_grid(self, qty, field, value):
unit = qty[field]
if not unit:
return ""
return unit["name"]
def render_value_for_grid(self, qty, field, value):
return qty["value"]["decimal"]
def get_instance(self):
quantity = self.farmos_client.resource.get_id(
"quantity", self.farmos_quantity_type, self.request.matchdict["uuid"]
@ -187,7 +228,7 @@ class QuantityMasterView(FarmOSMasterView):
def get_instance_title(self, quantity):
return quantity["value"]
def normalize_quantity(self, quantity):
def normalize_quantity(self, quantity, included={}):
if created := quantity["attributes"]["created"]:
created = datetime.datetime.fromisoformat(created)
@ -197,11 +238,37 @@ class QuantityMasterView(FarmOSMasterView):
changed = datetime.datetime.fromisoformat(changed)
changed = self.app.localtime(changed)
quantity_type_object = None
quantity_type_uuid = None
unit_object = None
unit_uuid = None
if relationships := quantity["relationships"]:
if quantity_type := relationships["quantity_type"]["data"]:
quantity_type_uuid = quantity_type["id"]
quantity_type_object = {
"uuid": quantity_type_uuid,
"type": "quantity_type--quantity_type",
}
if unit := relationships["units"]["data"]:
unit_uuid = unit["id"]
if unit := included.get(unit_uuid):
unit_object = {
"uuid": unit_uuid,
"type": "taxonomy_term--unit",
"name": unit["attributes"]["name"],
}
return {
"uuid": quantity["id"],
"drupal_id": quantity["attributes"]["drupal_internal__id"],
"quantity_type": quantity_type_object,
"quantity_type_uuid": quantity_type_uuid,
"measure": quantity["attributes"]["measure"],
"value": quantity["attributes"]["value"],
"unit": unit_object,
"unit_uuid": unit_uuid,
"label": quantity["attributes"]["label"] or colander.null,
"created": created,
"changed": changed,

View file

@ -29,7 +29,7 @@ from wuttaweb.db import Session
from wuttafarm.web.views import WuttaFarmMasterView
from wuttafarm.db.model import QuantityType, Quantity, StandardQuantity
from wuttafarm.web.forms.schema import UnitRef
from wuttafarm.web.forms.schema import UnitRef, LogRef
def get_quantity_type_enum(config):
@ -119,6 +119,7 @@ class QuantityMasterView(WuttaFarmMasterView):
"value",
"units",
"label",
"log",
"drupal_id",
"farmos_uuid",
]
@ -231,6 +232,13 @@ class QuantityMasterView(WuttaFarmMasterView):
# TODO: ugh
f.set_default("units", quantity.quantity.units)
# log
if self.creating or self.editing:
f.remove("log")
else:
f.set_node("log", LogRef(self.request))
f.set_default("log", quantity.log)
def get_xref_buttons(self, quantity):
buttons = super().get_xref_buttons(quantity)

View file

@ -28,6 +28,7 @@ import logging
from pyramid.renderers import render_to_response
from wuttaweb.views import View
from wuttaweb.db import Session
from wuttafarm.web.util import get_farmos_client_for_user
@ -40,6 +41,8 @@ class QuickFormView(View):
Base class for quick form views.
"""
Session = Session
def __init__(self, request, context=None):
super().__init__(request, context=context)
self.farmos_client = get_farmos_client_for_user(self.request)

View file

@ -34,7 +34,6 @@ from wuttaweb.forms.schema import WuttaDateTime
from wuttaweb.forms.widgets import WuttaDateTimeWidget
from wuttafarm.web.views.quick import QuickFormView
from wuttafarm.web.util import get_farmos_client_for_user
class EggsQuickForm(QuickFormView):
@ -49,6 +48,9 @@ class EggsQuickForm(QuickFormView):
_layer_assets = None
# TODO: make this configurable?
unit_name = "egg(s)"
def make_quick_form(self):
f = self.make_form(
fields=[
@ -89,6 +91,47 @@ class EggsQuickForm(QuickFormView):
if self._layer_assets is not None:
return self._layer_assets
if self.app.is_farmos_wrapper():
assets = self.get_layer_assets_from_farmos()
else:
assets = self.get_layer_assets_from_wuttafarm()
assets.sort(key=lambda a: a["name"])
self._layer_assets = assets
return assets
def get_layer_assets_from_wuttafarm(self):
model = self.app.model
session = self.Session()
assets = []
def normalize(asset):
asset_type = asset.__wutta_hint__["farmos_asset_type"]
return {
"uuid": str(asset.farmos_uuid),
"name": asset.asset_name,
"type": f"asset--{asset_type}",
}
query = (
session.query(model.AnimalAsset)
.join(model.Asset)
.filter(model.AnimalAsset.produces_eggs == True)
.order_by(model.Asset.asset_name)
)
assets.extend([normalize(a) for a in query])
query = (
session.query(model.GroupAsset)
.join(model.Asset)
.filter(model.GroupAsset.produces_eggs == True)
.order_by(model.Asset.asset_name)
)
assets.extend([normalize(a) for a in query])
return assets
def get_layer_assets_from_farmos(self):
assets = []
params = {
"filter[produces_eggs]": 1,
@ -108,24 +151,14 @@ class EggsQuickForm(QuickFormView):
result = self.farmos_client.asset.get("group", params=params)
assets.extend([normalize(a) for a in result["data"]])
assets.sort(key=lambda a: a["name"])
self._layer_assets = assets
return assets
def save_quick_form(self, form):
response = self.save_to_farmos(form)
log = json.loads(response["create-log#body{0}"]["body"])
if self.app.is_farmos_wrapper():
return self.save_to_farmos(form)
if self.app.is_farmos_mirror():
quantity = json.loads(response["create-quantity"]["body"])
client = get_farmos_client_for_user(self.request)
self.app.auto_sync_from_farmos(
quantity["data"], "StandardQuantity", client=client
)
self.app.auto_sync_from_farmos(log["data"], "HarvestLog", client=client)
return log
return self.save_to_wuttafarm(form)
def save_to_farmos(self, form):
data = form.validated
@ -135,7 +168,7 @@ class EggsQuickForm(QuickFormView):
asset = assets[data["asset"]]
# TODO: make this configurable?
unit_name = "egg(s)"
unit_name = self.unit_name
unit = {"data": {"type": "taxonomy_term--unit"}}
new_unit = None
@ -234,13 +267,87 @@ class EggsQuickForm(QuickFormView):
blueprints.insert(0, new_unit)
blueprint = SubrequestsBlueprint.parse_obj(blueprints)
response = self.farmos_client.subrequests.send(blueprint, format=Format.json)
return response
def redirect_after_save(self, result):
return self.redirect(
self.request.route_url(
"farmos_logs_harvest.view", uuid=result["data"]["id"]
log = json.loads(response["create-log#body{0}"]["body"])
if self.app.is_farmos_mirror():
if new_unit:
unit = json.loads(response["create-unit"]["body"])
self.app.auto_sync_from_farmos(
unit["data"], "Unit", client=self.farmos_client
)
quantity = json.loads(response["create-quantity"]["body"])
self.app.auto_sync_from_farmos(
quantity["data"], "StandardQuantity", client=self.farmos_client
)
self.app.auto_sync_from_farmos(
log["data"], "HarvestLog", client=self.farmos_client
)
return log
def save_to_wuttafarm(self, form):
model = self.app.model
session = self.Session()
data = form.validated
asset = (
session.query(model.Asset)
.filter(model.Asset.farmos_uuid == data["asset"])
.one()
)
# TODO: make this configurable?
unit_name = self.unit_name
new_unit = False
unit = session.query(model.Unit).filter(model.Unit.name == unit_name).first()
if not unit:
unit = model.Unit(name=unit_name)
session.add(unit)
new_unit = True
quantity = model.StandardQuantity(
quantity_type_id="standard",
measure_id="count",
value_numerator=data["count"],
value_denominator=1,
units=unit,
)
session.add(quantity)
log = model.HarvestLog(
log_type="harvest",
message=f"Collected {data['count']} {unit_name}",
timestamp=self.app.make_utc(data["timestamp"]),
notes=data["notes"] or None,
quick="eggs",
status="done",
)
session.add(log)
log.assets.append(asset)
log.quantities.append(quantity.quantity)
log.owners.append(self.request.user)
session.flush()
if self.app.is_farmos_mirror():
if new_unit:
self.app.auto_sync_to_farmos(unit, client=self.farmos_client)
self.app.auto_sync_to_farmos(quantity, client=self.farmos_client)
self.app.auto_sync_to_farmos(log, client=self.farmos_client)
return log
def redirect_after_save(self, log):
model = self.app.model
if isinstance(log, model.HarvestLog):
return self.redirect(
self.request.route_url("logs_harvest.view", uuid=log.uuid)
)
return self.redirect(
self.request.route_url("farmos_logs_harvest.view", uuid=log["data"]["id"])
)

View file

@ -24,7 +24,7 @@ Master view for Units
"""
from wuttafarm.web.views import WuttaFarmMasterView
from wuttafarm.db.model import Measure, Unit
from wuttafarm.db.model import Measure, Unit, Quantity
class MeasureView(WuttaFarmMasterView):
@ -52,6 +52,26 @@ class MeasureView(WuttaFarmMasterView):
"drupal_id",
]
has_rows = True
row_model_class = Quantity
rows_viewable = True
row_labels = {
"quantity_type_id": "Quantity Type ID",
"measure_id": "Measure ID",
}
row_grid_columns = [
"drupal_id",
"as_text",
"quantity_type",
"value",
"units",
"label",
]
rows_sort_defaults = ("drupal_id", "desc")
def configure_grid(self, grid):
g = grid
super().configure_grid(g)
@ -59,6 +79,37 @@ class MeasureView(WuttaFarmMasterView):
# name
g.set_link("name")
def get_row_grid_data(self, measure):
model = self.app.model
session = self.Session()
return session.query(model.Quantity).filter(model.Quantity.measure == measure)
def configure_row_grid(self, grid):
g = grid
super().configure_row_grid(g)
# drupal_id
g.set_label("drupal_id", "ID", column_only=True)
# as_text
g.set_renderer("as_text", self.render_as_text_for_grid)
g.set_link("as_text")
# value
g.set_renderer("value", self.render_value_for_grid)
def render_as_text_for_grid(self, quantity, field, value):
return quantity.render_as_text(self.config)
def render_value_for_grid(self, quantity, field, value):
value = quantity.value_numerator / quantity.value_denominator
return self.app.render_quantity(value)
def get_row_action_url_view(self, quantity, i):
return self.request.route_url(
f"quantities_{quantity.quantity_type_id}.view", uuid=quantity.uuid
)
@classmethod
def defaults(cls, config):
""" """
@ -104,6 +155,26 @@ class UnitView(WuttaFarmMasterView):
"farmos_uuid",
]
has_rows = True
row_model_class = Quantity
rows_viewable = True
row_labels = {
"quantity_type_id": "Quantity Type ID",
"measure_id": "Measure ID",
}
row_grid_columns = [
"drupal_id",
"as_text",
"quantity_type",
"measure",
"value",
"label",
]
rows_sort_defaults = ("drupal_id", "desc")
def configure_grid(self, grid):
g = grid
super().configure_grid(g)
@ -131,6 +202,37 @@ class UnitView(WuttaFarmMasterView):
return buttons
def get_row_grid_data(self, unit):
model = self.app.model
session = self.Session()
return session.query(model.Quantity).filter(model.Quantity.units == unit)
def configure_row_grid(self, grid):
g = grid
super().configure_row_grid(g)
# drupal_id
g.set_label("drupal_id", "ID", column_only=True)
# as_text
g.set_renderer("as_text", self.render_as_text_for_grid)
g.set_link("as_text")
# value
g.set_renderer("value", self.render_value_for_grid)
def render_as_text_for_grid(self, quantity, field, value):
return quantity.render_as_text(self.config)
def render_value_for_grid(self, quantity, field, value):
value = quantity.value_numerator / quantity.value_denominator
return self.app.render_quantity(value)
def get_row_action_url_view(self, quantity, i):
return self.request.route_url(
f"quantities_{quantity.quantity_type_id}.view", uuid=quantity.uuid
)
def defaults(config, **kwargs):
base = globals()