Skip to content

Commit

Permalink
Fixes netbox-community#16782: Add object filtering for custom fields
Browse files Browse the repository at this point in the history
  • Loading branch information
samk-acw committed Jul 26, 2024
1 parent e62a422 commit ee35388
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 4 deletions.
2 changes: 2 additions & 0 deletions docs/customization/custom-fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ If a default value is specified for a selection field, it must exactly match one

An object or multi-object custom field can be used to refer to a particular NetBox object or objects as the "value" for a custom field. These custom fields must define an `object_type`, which determines the type of object to which custom field instances point.

By default, an object choice field will make all objects of that type available for selection in the drop-down. The list choices can be filtered to only show objects with certain values by providing a `query_params` dict in the Related Object Filter field, as a JSON value. More information about `query_params` can be found [here](./custom-scripts.md#objectvar)

## Custom Fields in Templates

Several features within NetBox, such as export templates and webhooks, utilize Jinja2 templating. For convenience, objects which support custom field assignment expose custom field data through the `cf` property. This is a bit cleaner than accessing custom field data through the actual field (`custom_field_data`).
Expand Down
2 changes: 1 addition & 1 deletion netbox/extras/api/serializers_/customfields.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Meta:
fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'type', 'related_object_type', 'data_type',
'name', 'label', 'group_name', 'description', 'required', 'search_weight', 'filter_logic', 'ui_visible',
'ui_editable', 'is_cloneable', 'default', 'weight', 'validation_minimum', 'validation_maximum',
'ui_editable', 'is_cloneable', 'default', 'related_object_filter', 'weight', 'validation_minimum', 'validation_maximum',
'validation_regex', 'validation_unique', 'choice_set', 'comments', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
Expand Down
2 changes: 1 addition & 1 deletion netbox/extras/forms/model_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class CustomFieldForm(forms.ModelForm):
FieldSet(
'search_weight', 'filter_logic', 'ui_visible', 'ui_editable', 'weight', 'is_cloneable', name=_('Behavior')
),
FieldSet('default', 'choice_set', name=_('Values')),
FieldSet('default', 'choice_set', 'related_object_filter', name=_('Values')),
FieldSet(
'validation_minimum', 'validation_maximum', 'validation_regex', 'validation_unique', name=_('Validation')
),
Expand Down
18 changes: 18 additions & 0 deletions netbox/extras/migrations/0116_customfield_related_object_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.7 on 2024-07-19 07:31

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('extras', '0115_convert_dashboard_widgets'),
]

operations = [
migrations.AddField(
model_name='customfield',
name='related_object_filter',
field=models.JSONField(blank=True, null=True),
),
]
12 changes: 11 additions & 1 deletion netbox/extras/models/customfields.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
'Default value for the field (must be a JSON value). Encapsulate strings with double quotes (e.g. "Foo").'
)
)
related_object_filter = models.JSONField(
blank=True,
null=True,
help_text=_(
'Filter the object selection choices using a query_params dict (must be a JSON value).'
'Encapsulate strings with double quotes (e.g. "Foo").'
)
)
weight = models.PositiveSmallIntegerField(
default=100,
verbose_name=_('display weight'),
Expand Down Expand Up @@ -511,7 +519,8 @@ def to_form_field(self, set_initial=True, enforce_required=True, enforce_visibil
field = field_class(
queryset=model.objects.all(),
required=required,
initial=initial
initial=initial,
query_params=self.related_object_filter
)

# Multiple objects
Expand All @@ -522,6 +531,7 @@ def to_form_field(self, set_initial=True, enforce_required=True, enforce_visibil
queryset=model.objects.all(),
required=required,
initial=initial,
query_params=self.related_object_filter
)

# Text
Expand Down
2 changes: 1 addition & 1 deletion netbox/extras/tests/test_filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
class CustomFieldTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = CustomField.objects.all()
filterset = CustomFieldFilterSet
ignore_fields = ('default',)
ignore_fields = ('default', 'related_object_filter')

@classmethod
def setUpTestData(cls):
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/extras/customfield.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ <h5 class="card-header">{% trans "Custom Field" %}</h5>
<th scope="row">{% trans "Default Value" %}</th>
<td>{{ object.default }}</td>
</tr>
<tr>
<th scope="row">{% trans "Related object filter" %}</th>
<td>{{ object.related_object_filter }}</td>
</tr>
</table>
</div>
<div class="card">
Expand Down

0 comments on commit ee35388

Please sign in to comment.