Skip to content

Introduce a custom form field to represent generic foreign key relations #19821

@jeremystretch

Description

@jeremystretch

NetBox version

v4.3.3

Feature type

New functionality

Proposed functionality

Devise a new type of form field and widget capable of setting a GFK relation on an object. This is currently achieved by using two independent form fields which map to the two concrete model fields supporting the GFK (e.g. content_type and object_id).

Some quick prototyping suggests the new widget would look similar to the following:

from django import forms

class GenericForeignKeyWidget(forms.MultiWidget):
    def __init__(self, content_type_choices=None, attrs=None):
        widgets = [
            forms.Select(choices=content_type_choices),
            forms.TextInput(attrs={'placeholder': 'Object ID'}),
        ]
        super().__init__(widgets, attrs)

    def decompress(self, value):
        if value and hasattr(value, '_meta'):
            ct_id = ContentType.objects.get_for_model(value).pk
            return [ct_id, value.pk]
        return [None, None]

And the corresponding form field might look like this:

from django import forms
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError

class GenericForeignKeyFormField(forms.MultiValueField):
    def __init__(self, content_type_choices=None, **kwargs):
        fields = [
            forms.ChoiceField(choices=content_type_choices),
            forms.CharField()
        ]
        widget = GenericForeignKeyWidget(content_type_choices)
        super().__init__(fields=fields, widget=widget, **kwargs)

    def compress(self, data_list):
        if data_list and all(data_list):
            ct_id, obj_id = data_list
            try:
                content_type = ContentType.objects.get(pk=ct_id)
                model_class = content_type.model_class()
                return model_class.objects.get(pk=obj_id)
            except Exception as e:
                raise ValidationError(f"Invalid GenericForeignKey: {e}")
        return None

These examples will need to be modified to employ NetBox's REST API for object selection.

Use case

If proved viable, this approach will greatly simplify GFK relation handling within model forms by obviating the need to declare two form fields, and by reducing the amount of custom logic needed within each form's __init__() and save() methods.

Database changes

N/A

External dependencies

N/A

Metadata

Metadata

Assignees

No one assigned

    Labels

    complexity: highExpected to require a large amont of time and effort to implement relative to other tasksneeds milestoneAwaiting prioritization for inclusion with a future NetBox releasestatus: backlogAwaiting selection for worktopic: Custom FieldsFor any issues relating to the Custom Fields functionalitytype: featureIntroduction of new functionality to the application

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions