length_unit may not be null on PUT but not POST on Cables Endpoint #2148

Closed
opened 2025-12-29 17:22:41 +01:00 by adam · 5 comments
Owner

Originally created by @zachmoody on GitHub (Nov 27, 2018).

Environment

  • Python version: 3.6
  • NetBox version: 2.5-beta2

Steps to Reproduce

Updating a cable via PUT without specifying length_unit returns an error that the field cannot be null however the field isn't required on POST.

Expected Behavior

PUT and POST behavior should be the same.

Observed Behavior

PUT requires a field have a value that POST doesn't.

Originally created by @zachmoody on GitHub (Nov 27, 2018). <!-- NOTE: This form is only for reproducible bugs. If you need assistance with NetBox installation, or if you have a general question, DO NOT open an issue. Instead, post to our mailing list: https://groups.google.com/forum/#!forum/netbox-discuss Please describe the environment in which you are running NetBox. Be sure that you are running an unmodified instance of the latest stable release before submitting a bug report. --> ### Environment * Python version: 3.6 * NetBox version: 2.5-beta2 <!-- Describe in detail the steps that someone else can take to reproduce this bug using the current stable release of NetBox (or the current beta release where applicable). --> ### Steps to Reproduce Updating a cable via PUT without specifying length_unit returns an error that the field cannot be null however the field isn't required on POST. <!-- What did you expect to happen? --> ### Expected Behavior PUT and POST behavior should be the same. <!-- What happened instead? --> ### Observed Behavior PUT requires a field have a value that POST doesn't.
adam added the type: bugstatus: accepted labels 2025-12-29 17:22:41 +01:00
adam closed this issue 2025-12-29 17:22:41 +01:00
Author
Owner

@zachmoody commented on GitHub (Nov 28, 2018):

Ok, here's bit more detail. POST lets you create a cable without the length_unit field:

{
	"termination_a_type": "dcim.interface",
	"termination_a_id": 2349,
	"termination_a": 2349,
	"termination_b_type": "dcim.interface",
	"termination_b_id": 2382,
	"termination_b": 2382
}

If you do include it and set to null then you get the same error as PUT on POST
POSTing the json above results in this response:

$ curl -X POST -H "Authorization: Token abc123" -H "Content-Type: application/json" -H "Accept: application/json; indent=4" http://localhost:8000/api/dcim/cables/ --data @cable.json
{
    "id": 1,
    "termination_a_type": "dcim.interface",
    "termination_a_id": 1,
    "termination_a": {
        "id": 1,
        "url": "http://localhost:8000/api/dcim/interfaces/1/",
        "device": {
            "id": 1,
            "url": "http://localhost:8000/api/dcim/devices/1/",
            "name": "test",
            "display_name": "test"
        },
        "name": "et-0/1/0",
        "cable": 1
    },
    "termination_b_type": "dcim.interface",
    "termination_b_id": 2,
    "termination_b": {
        "id": 2,
        "url": "http://localhost:8000/api/dcim/interfaces/2/",
        "device": {
            "id": 2,
            "url": "http://localhost:8000/api/dcim/devices/2/",
            "name": "test1",
            "display_name": "test1"
        },
        "name": "et-0/1/0",
        "cable": 1
    },
    "type": null,
    "status": {
        "value": true,
        "label": "Connected"
    },
    "label": "",
    "color": "",
    "length": null,
    "length_unit": null
}

Which if you modify and repackaged into a PUT trips the error.

@zachmoody commented on GitHub (Nov 28, 2018): Ok, here's bit more detail. POST lets you create a cable without the `length_unit` field: ```json { "termination_a_type": "dcim.interface", "termination_a_id": 2349, "termination_a": 2349, "termination_b_type": "dcim.interface", "termination_b_id": 2382, "termination_b": 2382 } ``` If you do include it and set to `null` then you get the same error as PUT on POST POSTing the json above results in this response: ```sh $ curl -X POST -H "Authorization: Token abc123" -H "Content-Type: application/json" -H "Accept: application/json; indent=4" http://localhost:8000/api/dcim/cables/ --data @cable.json { "id": 1, "termination_a_type": "dcim.interface", "termination_a_id": 1, "termination_a": { "id": 1, "url": "http://localhost:8000/api/dcim/interfaces/1/", "device": { "id": 1, "url": "http://localhost:8000/api/dcim/devices/1/", "name": "test", "display_name": "test" }, "name": "et-0/1/0", "cable": 1 }, "termination_b_type": "dcim.interface", "termination_b_id": 2, "termination_b": { "id": 2, "url": "http://localhost:8000/api/dcim/interfaces/2/", "device": { "id": 2, "url": "http://localhost:8000/api/dcim/devices/2/", "name": "test1", "display_name": "test1" }, "name": "et-0/1/0", "cable": 1 }, "type": null, "status": { "value": true, "label": "Connected" }, "label": "", "color": "", "length": null, "length_unit": null } ``` Which if you modify and repackaged into a PUT trips the error.
Author
Owner

@jeremystretch commented on GitHub (Nov 30, 2018):

It seems this is happening because we're using a CharField for length_unit rather than an IntegerField. The notable distinction is that an IntegerField can be null whereas a CharField cannot (it can be blank, but not null).

We can change this to our custom NullableCharField, which stores empty values as null rather than "", but in the interest of maintaining consistency with other choice fields it might be preferable to switch to an IntegerField. This just means we would change from storing m, ft etc. to hard-coded integer values like we do for other fields.

I'm open to feedback.

@jeremystretch commented on GitHub (Nov 30, 2018): It seems this is happening because we're using a CharField for `length_unit` rather than an IntegerField. The notable distinction is that an IntegerField can be `null` whereas a CharField cannot (it can be _blank_, but not `null`). We can change this to our custom NullableCharField, which stores empty values as `null` rather than `""`, but in the interest of maintaining consistency with other choice fields it might be preferable to switch to an IntegerField. This just means we would change from storing `m`, `ft` etc. to hard-coded integer values like we do for other fields. I'm open to feedback.
Author
Owner

@lampwins commented on GitHub (Nov 30, 2018):

I vote for consistency here. We have a well-defined method for choice fields in that they use integer based fields with constants in the code base. This ensures consistency through the code base, but also in the way API clients interact with choice fields.

@lampwins commented on GitHub (Nov 30, 2018): I vote for consistency here. We have a well-defined method for choice fields in that they use integer based fields with constants in the code base. This ensures consistency through the code base, but also in the way API clients interact with choice fields.
Author
Owner

@jeremystretch commented on GitHub (Nov 30, 2018):

One additional thought: Sticking with integer values in the database makes future localization work a bit cleaner. For example, a Spanish speaker won't wonder why "pie" ("foot") is stored as "ft".

@jeremystretch commented on GitHub (Nov 30, 2018): One additional thought: Sticking with integer values in the database makes future localization work a bit cleaner. For example, a Spanish speaker won't wonder why "pie" ("foot") is stored as "ft".
Author
Owner

@jeremystretch commented on GitHub (Nov 30, 2018):

This also affects Rack.outer_unit. I'm changing that field to an IntegerField as well.

@jeremystretch commented on GitHub (Nov 30, 2018): This also affects Rack.outer_unit. I'm changing that field to an IntegerField as well.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#2148