Skip to content

Fix single-valued UID reference fields not settable through the JSON API - #106

Merged
xispa merged 2 commits into
2.xfrom
feature/fix-single-valued-uidreference
Oct 6, 2026
Merged

xispa merged 2 commits into
2.xfrom
feature/fix-single-valued-uidreference

Conversation

@ramonski

@ramonski ramonski commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

Description of the issue/feature this PR addresses

UIDReferenceFieldMixin.set always forwards the resolved references to the field setter as a list, even when the field is single-valued. AT UIDReferenceField validators reject a list value with [...] is not supported, so assigning a single-valued reference through @@API/senaite/v1/update (or create) fails — for example a Sample's Specification, Batch, SamplePoint or Template.

The classic ReferenceFieldManager already unwraps single-valued fields to a scalar; the UID reference mixin (used by both the AT and DX UID reference field managers) does not.

Current behavior before PR

Updating a single-valued UID reference field fails:

POST @@API/senaite/v1/update/<sample-uid>
{"Specification": "<spec-uid>"}

-> "['<spec-uid>'] is not supported."

The same happens with {"Specification": {"uid": "<spec-uid>"}}, because the value still reaches the field validator wrapped in a list.

Desired behavior after PR is merged

The reference is assigned. Non multi-valued fields receive a scalar UID (or None to clear); multi-valued fields keep the list, unchanged. DX UIDReferenceField.set already normalizes via to_list, so scalars are accepted there too — the change is safe for both field managers.

--

Reproduced against a live 2.x instance (assigning a Sample Specification). The fix mirrors the single-valued handling in ReferenceFieldManager.

I confirm I have coded it according to PEP8 standards.

The UIDReferenceFieldMixin always passed a list to the field setter, even
for single-valued fields. AT UIDReferenceField validators reject a list
value ('[...] is not supported'), so assigning e.g. a Sample's
Specification, Batch or SamplePoint through the API failed. Unwrap the
list to a scalar (or None to clear) for non multi-valued fields, matching
the classic ReferenceFieldManager.
@ramonski
ramonski requested a review from xispa July 28, 2026 16:49
@ramonski ramonski added the Bug 🐞 Something is broken label Jul 28, 2026
@xispa
xispa merged commit e6e9520 into 2.x Oct 6, 2026
2 checks passed
@xispa
xispa deleted the feature/fix-single-valued-uidreference branch October 6, 2026 10:55
ramonski added a commit that referenced this pull request Oct 7, 2026
Two separate faults, both of which end as a WrongContainedType or a
WrongType on a field the request never mentions.

#106 unwrapped a single valued reference from its list to a bare UID.
An Archetypes UIDReferenceField needs that, and refuses a list with
"[...] is not supported". A Dexterity UIDReferenceField derives from
zope.schema List and validates as one, so the bare UID fails before it
is ever stored, and setting e.g. a department's manager through the API
stopped working. The unwrapping moves to the Archetypes field manager,
through a to_field_value hook, so each side is handed the shape its own
validator expects.

The second fault is older and was hiding behind the first. A Dexterity
type migrated from Archetypes keeps the old capitalised name as a BBB
property, and a payload written against the old API uses it. get_field
looked the name up exactly, so the schema field was not found and the
data manager fell back to the BBB setter. Some of those setters convert
the value, and many hand it to the mutator as it came: a duration stays
the mapping JSON carried, a UID stays unicode.

The schema spellings are tried after the exact name, and only a
candidate naming a real field is used. There are 140 of these BBB
properties on Dexterity content, and 112 of them name a schema field.
Lowering the first letter reaches 43; the rest are snake case. A few
keep neither convention (a sample template calls its field
`samplepoint`), which is why the plain lower case form is tried too.

The new doctest covers both faults, and fails if either fix is
reverted.
ramonski added a commit that referenced this pull request Oct 7, 2026
Two separate faults, both of which end as a WrongContainedType or a
WrongType on a field the request never mentions.

#106 unwrapped a single valued reference from its list to a bare UID.
An Archetypes UIDReferenceField needs that, and refuses a list with
"[...] is not supported". A Dexterity UIDReferenceField derives from
zope.schema List and validates as one, so the bare UID fails before it
is ever stored, and setting e.g. a department's manager through the API
stopped working. The unwrapping moves to the Archetypes field manager,
through a to_field_value hook, so each side is handed the shape its own
validator expects.

The second fault is older and was hiding behind the first. A Dexterity
type migrated from Archetypes keeps the old capitalised name as a BBB
property, and a payload written against the old API uses it. get_field
looked the name up exactly, so the schema field was not found and the
data manager fell back to the BBB setter. Some of those setters convert
the value, and many hand it to the mutator as it came: a duration stays
the mapping JSON carried, a UID stays unicode.

The schema spellings are tried after the exact name, and only a
candidate naming a real field is used. There are 140 of these BBB
properties on Dexterity content, and 112 of them name a schema field.
Lowering the first letter reaches 43; the rest are snake case. A few
keep neither convention (a sample template calls its field
`samplepoint`), which is why the plain lower case form is tried too.

The new doctest covers both faults, and fails if either fix is
reverted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug 🐞 Something is broken

Development

Successfully merging this pull request may close these issues.

2 participants