Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 20 additions & 19 deletions docs/reference/filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,14 @@ These lookup expressions can be applied by adding a suffix to the desired field'

Numeric based fields (ASN, VLAN ID, etc) support these lookup expressions:

| Filter | Description |
|--------|-------------|
| `n` | Not equal to |
| `lt` | Less than |
| `lte` | Less than or equal to |
| `gt` | Greater than |
| `gte` | Greater than or equal to |
| Filter | Description |
|---------|--------------------------|
| `n` | Not equal to |
| `lt` | Less than |
| `lte` | Less than or equal to |
| `gt` | Greater than |
| `gte` | Greater than or equal to |
| `empty` | Is empty/null (boolean) |

Here is an example of a numeric field lookup expression that will return all VLANs with a VLAN ID greater than 900:

Expand All @@ -79,18 +80,18 @@ GET /api/ipam/vlans/?vid__gt=900

String based (char) fields (Name, Address, etc) support these lookup expressions:

| Filter | Description |
|--------|-------------|
| `n` | Not equal to |
| `ic` | Contains (case-insensitive) |
| `nic` | Does not contain (case-insensitive) |
| `isw` | Starts with (case-insensitive) |
| `nisw` | Does not start with (case-insensitive) |
| `iew` | Ends with (case-insensitive) |
| `niew` | Does not end with (case-insensitive) |
| `ie` | Exact match (case-insensitive) |
| `nie` | Inverse exact match (case-insensitive) |
| `empty` | Is empty (boolean) |
| Filter | Description |
|---------|----------------------------------------|
| `n` | Not equal to |
| `ic` | Contains (case-insensitive) |
| `nic` | Does not contain (case-insensitive) |
| `isw` | Starts with (case-insensitive) |
| `nisw` | Does not start with (case-insensitive) |
| `iew` | Ends with (case-insensitive) |
| `niew` | Does not end with (case-insensitive) |
| `ie` | Exact match (case-insensitive) |
| `nie` | Inverse exact match (case-insensitive) |
| `empty` | Is empty/null (boolean) |

Here is an example of a lookup expression on a string field that will return all devices with `switch` in the name:

Expand Down
3 changes: 2 additions & 1 deletion netbox/utilities/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
lte='lte',
lt='lt',
gte='gte',
gt='gt'
gt='gt',
empty='isnull',
)

FILTER_NEGATION_LOOKUP_MAP = dict(
Expand Down
25 changes: 25 additions & 0 deletions netbox/utilities/tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ class DummyModel(models.Model):
charfield = models.CharField(
max_length=10
)
numberfield = models.IntegerField(
blank=True,
null=True
)
choicefield = models.IntegerField(
choices=(('A', 1), ('B', 2), ('C', 3))
)
Expand All @@ -108,6 +112,7 @@ class BaseFilterSetTest(TestCase):
"""
class DummyFilterSet(BaseFilterSet):
charfield = django_filters.CharFilter()
numberfield = django_filters.NumberFilter()
macaddressfield = MACAddressFilter()
modelchoicefield = django_filters.ModelChoiceFilter(
field_name='integerfield', # We're pretending this is a ForeignKey field
Expand All @@ -132,6 +137,7 @@ class Meta:
model = DummyModel
fields = (
'charfield',
'numberfield',
'choicefield',
'datefield',
'datetimefield',
Expand Down Expand Up @@ -171,6 +177,25 @@ def test_char_filter(self):
self.assertEqual(self.filters['charfield__iew'].exclude, False)
self.assertEqual(self.filters['charfield__niew'].lookup_expr, 'iendswith')
self.assertEqual(self.filters['charfield__niew'].exclude, True)
self.assertEqual(self.filters['charfield__empty'].lookup_expr, 'empty')
self.assertEqual(self.filters['charfield__empty'].exclude, False)

def test_number_filter(self):
self.assertIsInstance(self.filters['numberfield'], django_filters.NumberFilter)
self.assertEqual(self.filters['numberfield'].lookup_expr, 'exact')
self.assertEqual(self.filters['numberfield'].exclude, False)
self.assertEqual(self.filters['numberfield__n'].lookup_expr, 'exact')
self.assertEqual(self.filters['numberfield__n'].exclude, True)
self.assertEqual(self.filters['numberfield__lt'].lookup_expr, 'lt')
self.assertEqual(self.filters['numberfield__lt'].exclude, False)
self.assertEqual(self.filters['numberfield__lte'].lookup_expr, 'lte')
self.assertEqual(self.filters['numberfield__lte'].exclude, False)
self.assertEqual(self.filters['numberfield__gt'].lookup_expr, 'gt')
self.assertEqual(self.filters['numberfield__gt'].exclude, False)
self.assertEqual(self.filters['numberfield__gte'].lookup_expr, 'gte')
self.assertEqual(self.filters['numberfield__gte'].exclude, False)
self.assertEqual(self.filters['numberfield__empty'].lookup_expr, 'isnull')
self.assertEqual(self.filters['numberfield__empty'].exclude, False)

def test_mac_address_filter(self):
self.assertIsInstance(self.filters['macaddressfield'], MACAddressFilter)
Expand Down