Cable Bulk Uploads allow blank status fields #11757

Closed
opened 2025-12-29 21:49:30 +01:00 by adam · 1 comment
Owner

Originally created by @cruse1977 on GitHub (Oct 21, 2025).

Originally assigned to: @arthanson on GitHub.

NetBox Edition

NetBox Community

NetBox Version

v4.4.4

Python Version

3.10

Steps to Reproduce

  1. Create a device, dmi-albany-rtr01, with Interfaces GigabitEthernet0/1/4 and GigabitEthernet0/1/5 in site "DM-Albany
  2. Bulk upload the following data:
side_a_device, side_a_type, side_a_name, side_b_device, side_b_type, side_b_name, side_a_site, side_b_site, status
"dmi01-albany-rtr01", "dcim.interface", "GigabitEthernet0/1/4", "dmi01-albany-rtr01", "dcim.interface", "GigabitEthernet0/1/5", "DM-Albany", "DM-Albany", ""

Note the status field isn't marked as mandatory but SHOULD be to be consistent with the UI

Expected Behavior

Upload is rejected as "" is not a valid status choice (the UI enforces a valid value being set)

Observed Behavior

Cable is allowed to be created with the below data

Image

The larger issue here is around netbox-branching - if in a branch and this action is undertake, the branch will fail to merge or in main fail to sync due to a validation error of status must be set

Originally created by @cruse1977 on GitHub (Oct 21, 2025). Originally assigned to: @arthanson on GitHub. ### NetBox Edition NetBox Community ### NetBox Version v4.4.4 ### Python Version 3.10 ### Steps to Reproduce 1. Create a device, dmi-albany-rtr01, with Interfaces GigabitEthernet0/1/4 and GigabitEthernet0/1/5 in site "DM-Albany 2. Bulk upload the following data: ``` side_a_device, side_a_type, side_a_name, side_b_device, side_b_type, side_b_name, side_a_site, side_b_site, status "dmi01-albany-rtr01", "dcim.interface", "GigabitEthernet0/1/4", "dmi01-albany-rtr01", "dcim.interface", "GigabitEthernet0/1/5", "DM-Albany", "DM-Albany", "" ``` Note the status field isn't marked as mandatory but SHOULD be to be consistent with the UI ### Expected Behavior Upload is rejected as "" is not a valid status choice (the UI enforces a valid value being set) ### Observed Behavior Cable is allowed to be created with the below data <img width="1690" height="761" alt="Image" src="https://github.com/user-attachments/assets/de847230-fb4d-44f3-b862-72d7b0f7ae65" /> The larger issue here is around netbox-branching - if in a branch and this action is undertake, the branch will fail to merge or in main fail to sync due to a validation error of **status must be set**
adam added the type: bugstatus: acceptednetboxseverity: low labels 2025-12-29 21:49:30 +01:00
adam closed this issue 2025-12-29 21:49:30 +01:00
Author
Owner

@pheus commented on GitHub (Oct 28, 2025):

Thanks for the clear report and repro steps — this was super helpful!

What I’m seeing

  • The behavior isn’t limited to Cable status: it shows up with any ChoiceField that has a model default.
  • When the CSV column is present but blank (e.g., status,), the form passes an empty string ("") which then gets saved, instead of letting the model’s default apply.

Why it happens (short version)

  • Django only preserves a model’s default when the widget reports that the value was omitted.
  • A CSV cell that’s present-but-empty is not considered “omitted” by the default Select widget, so the empty string is treated as a real value and gets assigned.

Early attempt

  • I tried a generic approach that overrides the Select widget to treat blank/whitespace-only CSV cells as “omitted.”
  • Initial tests look promising:
    • If the model field has a default, the blank cell is treated as omitted → default (or existing value) is kept.
    • If the model field has no default, a blank cell still assigns "", so users can clear the value when that’s allowed.
  • This definitely needs more testing across apps to ensure we don’t surprise any non-CSV forms that rely on current behavior.

Two possible directions

  1. Generic (global) widget change: patch Select.value_omitted_from_data() so present‑but‑blank acts like omitted everywhere.

    • One place to maintain; fixes all ChoiceFields with defaults.
    • ⚠️ Risk of impacting regular HTML forms, not just CSV imports.
  2. CSV‑scoped change: apply the same “blank ⇒ omitted” logic only to the widgets used by CSV import fields (e.g., CSVChoiceField).

    • Safer for UI; still DRY for imports.
    • ⚠️ Slightly narrower scope; plugins using custom widgets may need the wrapper/opt‑in.

Ask

  • Does the project prefer the global fix (generic Select) or a CSV‑scoped fix (only for import fields like CSVChoiceField)?
  • Happy to help with a small PR and tests once we agree on the scope.

Thanks again for raising this!

@pheus commented on GitHub (Oct 28, 2025): Thanks for the clear report and repro steps — this was super helpful! **What I’m seeing** - The behavior isn’t limited to Cable status: it shows up with any **ChoiceField** that has a **model default**. - When the CSV column is **present but blank** (e.g., `status,`), the form passes an empty string (`""`) which then gets saved, instead of letting the model’s default apply. **Why it happens (short version)** - Django only preserves a model’s default when the **widget** reports that the value was **omitted**. - A CSV cell that’s present-but-empty is not considered “omitted” by the default `Select` widget, so the empty string is treated as a real value and gets assigned. **Early attempt** - I tried a generic approach that **overrides the `Select` widget** to treat blank/whitespace-only CSV cells as “omitted.” - Initial tests look promising: - If the model field **has a default**, the blank cell is treated as omitted → default (or existing value) is kept. - If the model field **has no default**, a blank cell still assigns `""`, so users can clear the value when that’s allowed. - This definitely needs more testing across apps to ensure we don’t surprise any non-CSV forms that rely on current behavior. **Two possible directions** 1. **Generic (global) widget change**: patch `Select.value_omitted_from_data()` so present‑but‑blank acts like omitted everywhere. - ✅ One place to maintain; fixes all ChoiceFields with defaults. - ⚠️ Risk of impacting regular HTML forms, not just CSV imports. 2. **CSV‑scoped change**: apply the same “blank ⇒ omitted” logic only to the widgets used by CSV import fields (e.g., `CSVChoiceField`). - ✅ Safer for UI; still DRY for imports. - ⚠️ Slightly narrower scope; plugins using custom widgets may need the wrapper/opt‑in. **Ask** - Does the project prefer the **global** fix (generic `Select`) or a **CSV‑scoped** fix (only for import fields like `CSVChoiceField`)? - Happy to help with a small PR and tests once we agree on the scope. Thanks again for raising this!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11757