Closes #645: Omit hidden fields from custom object create/edit and bulk edit forms - #663
Conversation
…dit forms A field with ui_editable=hidden was only disabled, not excluded, on the CustomObjectEditView and CustomObjectBulkEditView forms. The templates render every field in custom_object_type_field_groups unconditionally without checking disabled state, so a hidden field still rendered as an input -- matching core NetBox's convention where ui_editable=HIDDEN means a field is excluded from the form entirely (ui_editable=NO/read-only is still shown, just disabled). Exclude hidden fields' backing column(s) via Meta.exclude and skip them in both form-building loops, mirroring the existing CSV bulk-import handling (#626). Closes: #645
b1de02f to
7cbefb3
Compare
… drop dead branch - get_form() on both views now fetches custom_object_type.fields once and reuses that list for poly-object exclusion, hidden-field exclusion, and the per-field render loop, instead of issuing 3-4 separate queries. - _hidden_field_raw_columns() now calls CoordinatesFieldType.latitude/ longitude_field_name() instead of duplicating that naming convention. - Removed the polymorphic-object branch in _hidden_field_raw_columns(): poly_obj_raw_exclude already excludes those columns unconditionally at both call sites, so it never contributed anything.
|
@claude /review and keep response limited to actionable issues. |
|
Claude finished @bctiemann's task in 1m 46s —— View job Code Review
The approach is sound and mirrors core NetBox's pattern correctly. Two actionable issues: 1. Hidden coordinates field is untested
2. Tests don't assert the complementary caseBoth tests verify that Adding Otherwise the implementation is clean: the query deduplication ( |
|
@claude just curious, do you have access to the session context from the review previously requested? |
|
Claude finished @bctiemann's task in 19s —— View job AnswerNo — each What I can see is the output that was posted to this PR's comment thread (the previous review results are included in the context I receive as In short: the artifact (the posted review) is visible to me; the session that produced it is not. |
- test_edit_form_omits_hidden_field / test_bulk_edit_form_omits_hidden_field now also assert a ui_editable=no (read-only) field stays in base_fields, pinning the distinction from HIDDEN that this fix depends on. - Added dedicated tests for a hidden coordinates field, which excludes two backing columns (latitude/longitude) instead of one -- the one branch of _hidden_field_raw_columns() the existing tests didn't exercise.
|
Added test coverage. |
pheus
left a comment
There was a problem hiding this comment.
Thanks!
I found one blocking issue with hidden non-polymorphic multi-object fields: skipping them here also bypasses the view-level initialization and persistence path, so their configured defaults are no longer applied when creating an object. This appears to reintroduce the behavior fixed in #42.
Once that path is preserved and covered by a save-level regression test, the rest looks good to me.
| # Hidden fields are omitted entirely, not just disabled. | ||
| if field.ui_editable == CustomFieldUIEditableChoices.HIDDEN: | ||
| continue |
There was a problem hiding this comment.
Could we preserve the configured default for hidden multiobject fields here?
Skipping the field at this point also removes it from custom_object_type_fields, which is later used to initialize and save non-polymorphic multi-object relations. As these fields do not have a model-level default, creating an object with a hidden field would silently omit its configured default, reintroducing the behavior fixed in #42.
I think we need to keep the field out of the form while still applying its default during creation. It would also be helpful to cover this with a save-level regression test. Existing relations should remain unchanged when editing an object.
There was a problem hiding this comment.
Thanks for catching this; fixed and covered with a new test.
…ations A hidden non-polymorphic MultiObject field is a real M2M model attribute, not a rendering-only concept. Skipping it entirely from custom_object_type_fields (as the earlier fix did) meant custom_init's default-population and custom_save's M2M-persistence logic never ran for it -- reintroducing #42's bug (configured defaults not applied) for any hidden MultiObject field, and additionally risking clearing an existing relation on edit since cleaned_data has no key for an unrendered field. - Track hidden non-polymorphic MultiObject fields in custom_object_type_fields for bookkeeping only (never rendered; nothing reads that dict in a template). - custom_init stashes the resolved default IDs on self, since a hidden field has no form field to carry kwargs['initial'] into cleaned_data. - custom_save applies that resolved default on create, and leaves the relation untouched on edit -- consistent with a hidden field being neither displayed nor editable. - Added regression tests for both the create-with-default and edit-preserves-existing-relation cases. Thanks to @pheus for catching this in review.
pheus
left a comment
There was a problem hiding this comment.
Thanks for addressing this.
Closes: #645
Summary
CustomObjectTypeFieldwithui_editableset to "Hidden" was rendered as an (unlabeled-looking, but present) input on the object create/edit form and the bulk edit form, instead of being omitted entirely.get_annotated_form_field()only ever setsdisabled = Truefor anyui_editablevalue other than "Yes" -- it doesn't distinguish "Hidden" (should not be displayed at all) from "No"/read-only (should be displayed, but disabled). The templates render every field listed incustom_object_type_field_groupsunconditionally, without checkingdisabled, so bothCustomObjectEditView.get_form()andCustomObjectBulkEditView.get_form()ended up including hidden fields as still-visible inputs.extras.forms.mixins.NetBoxModelMixin._get_custom_fields), which filters outui_editable=HIDDENcustom fields before building the form, while leavingNO(read-only) fields in place as disabled.Changes
_hidden_field_raw_columns()helper inviews.py: given a queryset of fields, returns the backing model column name(s) for any field whoseui_editableisHIDDEN(handling coordinates' two-column and polymorphic-object raw-column cases).CustomObjectEditView.get_form()andCustomObjectBulkEditView.get_form()now:Meta.exclude, so theModelFormmetaclass doesn't auto-generate a plain (non-disabled) field for them fromfields="__all__".attrs, so they're never added tocustom_object_type_fields/_field_groups/_rendered_names.Testing
test_edit_form_omits_hidden_fieldandtest_bulk_edit_form_omits_hidden_fieldintest_views.py, asserting a hidden field's name is absent fromform.base_fields.main(Django 6.0.7) and afeature-branch commit with Django 6.1 pinned.