Filtering cables by terminations in the API returns wrong results #7096

Closed
opened 2025-12-29 20:19:14 +01:00 by adam · 1 comment
Owner

Originally created by @kkthxbye-code on GitHub (Oct 11, 2022).

Originally assigned to: @arthanson on GitHub.

NetBox version

v3.3.5

Python version

3.10

Steps to Reproduce

We discussed this on slack. Reproduction steps will be a little lackluster, but if needed I'll try to improve them.

  1. Create a device testdevice
  2. Create an interface inf1
  3. Create a rearport rp1 and a frontport fp1
  4. Remember the id of inf1 and fp1 - for the sake of this example, let's say inf1 has id 123 and fp1 has id 999.
  5. Create a cable between the interface and the frontport
  6. Try to filter for any cable with a termination with the type dcim.interface and the id 999.

https://netboxurl/api/dcim/cables/?termination_b_type=dcim.interface&termination_b_id=999

Expected Behavior

The API request should match any cables where one of the terminations has an id of 999 and the type dcim.interface.

Observed Behavior

A cable where one of the terminations is of type dcim.frontport and the id is 999.

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 140,
            "url": "https://demo.netbox.dev/api/dcim/cables/140/",
            "display": "#140",
            "type": "",
            "a_terminations": [
                {
                    "object_type": "dcim.frontport",
                    "object_id": 999,
                    "object": {
                        "id": 999,
                        "url": "https://demo.netbox.dev/api/dcim/front-ports/999/",
                        "display": "fp1",
                        "device": {
                            "id": 119,
                            "url": "https://demo.netbox.dev/api/dcim/devices/119/",
                            "display": "testdevice123",
                            "name": "testdevice123"
                        },
                        "name": "fp1",
                        "cable": 140,
                        "_occupied": true
                    }
                }
            ],
            "b_terminations": [
                {
                    "object_type": "dcim.interface",
                    "object_id": 1832,
                    "object": {
                        "id": 1832,
                        "url": "https://demo.netbox.dev/api/dcim/interfaces/1832/",
                        "display": "interface2",
                        "device": {
                            "id": 120,
                            "url": "https://demo.netbox.dev/api/dcim/devices/120/",
                            "display": "testdevice321",
                            "name": "testdevice321"
                        },
                        "name": "interface2",
                        "cable": 140,
                        "_occupied": true
                    }
                }
            ],
         ...
        }
    ]
}

The generated SQL looks like this:

SELECT DISTINCT "dcim_cable"."id",
       "dcim_cable"."created",
       "dcim_cable"."last_updated",
       "dcim_cable"."custom_field_data",
       "dcim_cable"."type",
       "dcim_cable"."status",
       "dcim_cable"."tenant_id",
       "dcim_cable"."label",
       "dcim_cable"."color",
       "dcim_cable"."length",
       "dcim_cable"."length_unit",
       "dcim_cable"."_abs_length"
  FROM "dcim_cable"
 INNER JOIN "dcim_cabletermination"
    ON ("dcim_cable"."id" = "dcim_cabletermination"."cable_id")
 INNER JOIN "django_content_type"
    ON ("dcim_cabletermination"."termination_type_id" = "django_content_type"."id")
 INNER JOIN "dcim_cabletermination" T4
    ON ("dcim_cable"."id" = T4."cable_id")
 WHERE ("django_content_type"."app_label" = 'dcim' AND "django_content_type"."model" = 'interface' AND T4."termination_id" = 999)
 ORDER BY "dcim_cable"."id" ASC
 LIMIT 50

The issue is that id and content type is matches independently, so if just one of the terminations is of the type dcim.interface it matches, regardless if that was the termination with the correct ID.

termination_b_type/termination_b_id and termination_a_type/termination_a_id also matches the same thing, not sure if this is intended and the a/b end are just for ease of visualization.

Originally created by @kkthxbye-code on GitHub (Oct 11, 2022). Originally assigned to: @arthanson on GitHub. ### NetBox version v3.3.5 ### Python version 3.10 ### Steps to Reproduce We discussed this on slack. Reproduction steps will be a little lackluster, but if needed I'll try to improve them. 1. Create a device testdevice 2. Create an interface inf1 3. Create a rearport rp1 and a frontport fp1 4. Remember the id of inf1 and fp1 - for the sake of this example, let's say inf1 has id 123 and fp1 has id 999. 5. Create a cable between the interface and the frontport 6. Try to filter for any cable with a termination with the type `dcim.interface` and the id 999. https://netboxurl/api/dcim/cables/?termination_b_type=dcim.interface&termination_b_id=999 ### Expected Behavior The API request should match any cables where one of the terminations has an id of 999 and the type `dcim.interface`. ### Observed Behavior A cable where one of the terminations is of type dcim.frontport and the id is 999. ``` { "count": 1, "next": null, "previous": null, "results": [ { "id": 140, "url": "https://demo.netbox.dev/api/dcim/cables/140/", "display": "#140", "type": "", "a_terminations": [ { "object_type": "dcim.frontport", "object_id": 999, "object": { "id": 999, "url": "https://demo.netbox.dev/api/dcim/front-ports/999/", "display": "fp1", "device": { "id": 119, "url": "https://demo.netbox.dev/api/dcim/devices/119/", "display": "testdevice123", "name": "testdevice123" }, "name": "fp1", "cable": 140, "_occupied": true } } ], "b_terminations": [ { "object_type": "dcim.interface", "object_id": 1832, "object": { "id": 1832, "url": "https://demo.netbox.dev/api/dcim/interfaces/1832/", "display": "interface2", "device": { "id": 120, "url": "https://demo.netbox.dev/api/dcim/devices/120/", "display": "testdevice321", "name": "testdevice321" }, "name": "interface2", "cable": 140, "_occupied": true } } ], ... } ] } ``` The generated SQL looks like this: ``` SELECT DISTINCT "dcim_cable"."id", "dcim_cable"."created", "dcim_cable"."last_updated", "dcim_cable"."custom_field_data", "dcim_cable"."type", "dcim_cable"."status", "dcim_cable"."tenant_id", "dcim_cable"."label", "dcim_cable"."color", "dcim_cable"."length", "dcim_cable"."length_unit", "dcim_cable"."_abs_length" FROM "dcim_cable" INNER JOIN "dcim_cabletermination" ON ("dcim_cable"."id" = "dcim_cabletermination"."cable_id") INNER JOIN "django_content_type" ON ("dcim_cabletermination"."termination_type_id" = "django_content_type"."id") INNER JOIN "dcim_cabletermination" T4 ON ("dcim_cable"."id" = T4."cable_id") WHERE ("django_content_type"."app_label" = 'dcim' AND "django_content_type"."model" = 'interface' AND T4."termination_id" = 999) ORDER BY "dcim_cable"."id" ASC LIMIT 50 ``` The issue is that id and content type is matches independently, so if just one of the terminations is of the type dcim.interface it matches, regardless if that was the termination with the correct ID. termination_b_type/termination_b_id and termination_a_type/termination_a_id also matches the same thing, not sure if this is intended and the a/b end are just for ease of visualization.
adam added the type: bugstatus: accepted labels 2025-12-29 20:19:14 +01:00
adam closed this issue 2025-12-29 20:19:14 +01:00
Author
Owner

@github-actions[bot] commented on GitHub (Jan 31, 2023):

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. Do not attempt to circumvent this process by "bumping" the issue; doing so will result in its immediate closure and you may be barred from participating in any future discussions. Please see our contributing guide.

@github-actions[bot] commented on GitHub (Jan 31, 2023): This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. **Do not** attempt to circumvent this process by "bumping" the issue; doing so will result in its immediate closure and you may be barred from participating in any future discussions. Please see our [contributing guide](https://github.com/netbox-community/netbox/blob/develop/CONTRIBUTING.md).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#7096