Repository navigation
Extract the file-field abstraction into the library - #33
Merged
domdinicola merged 2 commits intoOct 8, 2026
Merged
Conversation
Promotes the generic parts of the flex-file offload from Country Workspace so that consumers share one field type and one reference format instead of each redefining them.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #33 +/- ##
===========================================
+ Coverage 95.62% 95.83% +0.20%
===========================================
Files 28 29 +1
Lines 1372 1441 +69
Branches 149 157 +8
===========================================
+ Hits 1312 1381 +69
Misses 40 40
Partials 20 20 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
roma-valor
marked this pull request as ready for review
October 2, 2026 09:09
vitali-yanushchyk-valor
approved these changes
Oct 5, 2026
saxix
approved these changes
Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AB#320213
Follow-up to the review on unicef/hope-country-workspace#466, which asked to
keep the offload itself in Country Workspace and promote only the generic
field abstraction here.
Closes #32
What moves into the library
FlexImageField/FlexImageInputplus theflex_image_widgettemplate,now the canonical IMAGE field. The value is a
flexfile:<uuid>reference,not the payload.
clean()validates the upload and then returns thereference already on the record: only the consuming project holds both the
uploaded file and the record to attach it to, so it is the only place that
can store the payload and mint a new reference. A
clean()that returnedthe file would put bytes into data meant to stay JSON.
hope_flex_fields.references, owning the reference scheme and nothing else:is_reference,is_data_uri,format_reference,parse_reference,flex_file_src, and theREFERENCE_PREFIX/DATA_URI_FORMAT/DATA_URI_PREFIX/DEFAULT_MIMETYPEconstants.parse_referencereturnsNoneon a malformed value rather than raising, since these come from userdata and from records written before the offload.
FILE_URL_NAMEconfig entry, reversed with the file id, soflex_file_srccan build payload URLs without knowing a project's routes.CW sets it to
workspace:flex_file. Unset or unreversible yields""plusa warning, and the widget then renders the raw value as text instead of a
broken image.
Base64ImageField/Base64ImageInputas deprecated shims, kept for onerelease. They are deliberately not registered: seeding a
FieldDefinitionfor a deprecated type on every fresh install would offerit to users who should not pick it, so a project still migrating away
registers it itself (CW already does this in its reverse script). The
deprecated widget inherits the new rendering, which handles both references
and legacy
data:URIs, so swapping the field type and migrating the storeddata can land in either order.
The discovery API asked for in #32 (
field.is_file,DataChecker.get_file_field_names(with_prefix=...)) already shipped in 0.8.4and 0.9; this PR documents it rather than changing it.
What deliberately stays with the consumer
Storage and access control: the
FlexFieldFilemodel, the storage helpers,the tenant/program-scoped view that serves payloads, and the data migration.
Those depend on CW's
Validable,pghistoryand RDP flows, and are out ofscope per the review.
Migration note, worth a look
0018_add_fleximagefieldseeds theFieldDefinitionby repointing any rowalready under that name, rather than calling
create_default_fields.FieldDefinition.nameis unique, and CW already has aFlexImageFieldrowpointing at its own class, so a blind
get_or_create(name=..., field_type=...)would fail the unique constraint on upgrade. The update also goes through the
queryset so the old
field_typeis never deserialized, which would raise assoon as CW drops its class. This keeps the CW-side change to deleting its
local classes and importing from here.
Decisions I would like confirmed
devgroup only, needed to exercise the upload path. Thelibrary now registers an image field that any install can select, and
forms.ImageField.to_pythondoes an unguardedfrom PIL import Image, so aconsumer without Pillow gets an
ImportErroron upload. Django has the samegap, hence the conservative choice, and CW already declares
pillow>=12.3.Happy to promote it to a runtime dependency or an extra instead.
get_file_field_namesis unchanged. Extract file-field abstraction from CW PR 466 #32 describes CW's union wrapper as aworkaround, but the
with_prefixparameter already covers both forms, soCW's remaining two-liner is a convenience for call sites keying on either
name. Say the word if you want a single call returning the union.
Testing
205 tests pass, up from 148.
references.py,fields.pyandwidgets.pyareat 100% line and branch coverage. New tests cover malformed references, legacy
data:pass-through,None/empty handling, the unset and unreversible routecases, upload/clear/no-change paths through
clean(), widget rendering forreference, legacy and unresolvable values, and the migration repointing a
definition a project already owns without duplicating it.
tests/test_api.pymoves its object count 34 -> 35, as it did whenIdentityFieldwas added in #25, since one more field type is registered bydefault.