fix(recipe): measurement_interval_minutes e image_path si possono di nuovo azzerare (#37.3)
recipe_editor.html saveRecipe(): i due campi vengono sempre inviati nel payload (valore o null esplicito), non più omessi quando svuotati. recipe_service.py _header_fields(): per i due campi (unica eccezione concordata al confine dei lotti, righe ~37-60) distingue "non inviato" da "inviato null" con model_fields_set, invece di getattr(...) is not None — altrimenti un null esplicito veniva scartato allo stesso modo di un campo assente e il valore restava bloccato per sempre. Gli altri campi header (name, description, requires_*, allow_manual_input) non toccati. Test backend in test_recipes.py: TestUpdateRecipeClearNullableFields. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,13 +34,34 @@ HEADER_FIELDS = (
|
||||
)
|
||||
|
||||
|
||||
# image_path and measurement_interval_minutes are nullable columns where the
|
||||
# caller may deliberately want to clear the value (send null), not merely
|
||||
# leave it untouched by not mentioning the field at all. A plain
|
||||
# "getattr(...) is not None" check cannot tell those two cases apart -
|
||||
# once set, neither field could ever be cleared again (#37.3). The other
|
||||
# header fields keep that simpler check: booleans are always sent by the
|
||||
# client (never null) and clearing name/description to null is not a case
|
||||
# this endpoint needs to support.
|
||||
_NULLABLE_HEADER_FIELDS = ("image_path", "measurement_interval_minutes")
|
||||
|
||||
|
||||
def _header_fields(data: RecipeUpdate) -> dict:
|
||||
"""The header columns the caller actually asked to change."""
|
||||
return {
|
||||
field: getattr(data, field)
|
||||
for field in HEADER_FIELDS
|
||||
if getattr(data, field) is not None
|
||||
}
|
||||
"""The header columns the caller actually asked to change.
|
||||
|
||||
For image_path/measurement_interval_minutes, "asked to change" includes
|
||||
explicitly setting it to null - told apart from "field absent from the
|
||||
request" via model_fields_set, since RecipeUpdate defaults both to None.
|
||||
"""
|
||||
result = {}
|
||||
for field in HEADER_FIELDS:
|
||||
if field in _NULLABLE_HEADER_FIELDS:
|
||||
if field in data.model_fields_set:
|
||||
result[field] = getattr(data, field)
|
||||
else:
|
||||
value = getattr(data, field)
|
||||
if value is not None:
|
||||
result[field] = value
|
||||
return result
|
||||
|
||||
|
||||
async def _get_recipe_or_404(db: AsyncSession, recipe_id: int) -> Recipe:
|
||||
|
||||
Reference in New Issue
Block a user