All foreign keys to ContentType should use robust filtering for limit_choices_to #3147

Closed
opened 2025-12-29 18:26:07 +01:00 by adam · 1 comment
Owner

Originally created by @jeremystretch on GitHub (Jan 10, 2020).

Originally assigned to: @jeremystretch on GitHub.

Proposed Changes

Ensure that all model fields equating to ForeignKey(to=ContentType) where limit_choices_to is in use employ robust filtering by both app and model name.

Justification

There are several models in NetBox which have one or more ForeignKey fields to ContentType and utilize limit_choices_to to constrain the available choices. In all instances where the set of ContentTypes is constrained, a concise list of (app, model) pairings should be used. For example, the Cable model currently has:

CABLE_TERMINATION_TYPES = [
    'consoleport',
    'consoleserverport',
    'interface',
    ...
]

class Cable(...):
    termination_a_type = models.ForeignKey(
        to=ContentType,
        limit_choices_to={'model__in': CABLE_TERMINATION_TYPES},
        on_delete=models.PROTECT,
        related_name='+'
    )

This is problematic, because it allows for a potential name collision across apps within NetBox. Although not currently an issue, we would do well to address this before it presents a problem.

The above instance should be changed to use the model_names_to_filter_dict() and an explicit list of (app, model) pairings to filter the field's associated queryset:

CABLE_TERMINATION_MODELS = (
    'dcim.consoleport',
    'dcim.consoleserverport',
    'dcim.interface',
    ...
)

def get_cable_termination_models():
    return model_names_to_filter_dict(CABLE_TERMINATION_MODELS)

class Cable(...):
    termination_a_type = models.ForeignKey(
        to=ContentType,
        limit_choices_to=get_cable_termination_models(),
        on_delete=models.PROTECT,
        related_name='+'
    )

This change also entails extending the model_names_to_filter_dict() function to match on both app_label and model; it currently matches only on model. A set of Q objects can be used to achieve this.

Originally created by @jeremystretch on GitHub (Jan 10, 2020). Originally assigned to: @jeremystretch on GitHub. ### Proposed Changes Ensure that all model fields equating to `ForeignKey(to=ContentType)` where `limit_choices_to` is in use employ robust filtering by both app *and* model name. ### Justification There are several models in NetBox which have one or more ForeignKey fields to ContentType and utilize `limit_choices_to` to constrain the available choices. In all instances where the set of ContentTypes is constrained, a concise list of (app, model) pairings should be used. For example, the Cable model currently has: ```python CABLE_TERMINATION_TYPES = [ 'consoleport', 'consoleserverport', 'interface', ... ] class Cable(...): termination_a_type = models.ForeignKey( to=ContentType, limit_choices_to={'model__in': CABLE_TERMINATION_TYPES}, on_delete=models.PROTECT, related_name='+' ) ``` This is problematic, because it allows for a potential name collision across apps within NetBox. Although not currently an issue, we would do well to address this before it presents a problem. The above instance should be changed to use the `model_names_to_filter_dict()` and an explicit list of (app, model) pairings to filter the field's associated queryset: ```python CABLE_TERMINATION_MODELS = ( 'dcim.consoleport', 'dcim.consoleserverport', 'dcim.interface', ... ) def get_cable_termination_models(): return model_names_to_filter_dict(CABLE_TERMINATION_MODELS) class Cable(...): termination_a_type = models.ForeignKey( to=ContentType, limit_choices_to=get_cable_termination_models(), on_delete=models.PROTECT, related_name='+' ) ``` This change also entails extending the `model_names_to_filter_dict()` function to match on both `app_label` and `model`; it currently matches only on `model`. A set of `Q` objects can be used to achieve this.
adam added the status: acceptedtype: housekeeping labels 2025-12-29 18:26:07 +01:00
adam closed this issue 2025-12-29 18:26:07 +01:00
Author
Owner

@jeremystretch commented on GitHub (Jan 15, 2020):

I ended up ditching the <app>.<model> format altogether, since these constants ultimately are used to filter ContentType querysets anyway. I have replaced each list of strings with a static Q() object defining the specific query filter to be used.

@jeremystretch commented on GitHub (Jan 15, 2020): I ended up ditching the `<app>.<model>` format altogether, since these constants ultimately are used to filter ContentType querysets anyway. I have replaced each list of strings with a static `Q()` object defining the specific query filter to be used.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#3147