mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Closes #6138: Add an 'empty' filter modifier for character fields
This commit is contained in:
@ -4,6 +4,7 @@
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [#6138](https://github.com/netbox-community/netbox/issues/6138) - Add an `empty` filter modifier for character fields
|
||||
* [#6620](https://github.com/netbox-community/netbox/issues/6620) - Show assigned VMs count under device role view
|
||||
* [#6666](https://github.com/netbox-community/netbox/issues/6666) - Show management-only status under interface detail view
|
||||
* [#6667](https://github.com/netbox-community/netbox/issues/6667) - Display VM memory as GB/TB as appropriate
|
||||
|
@ -61,25 +61,30 @@ 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:
|
||||
|
||||
- `n` - not equal to (negation)
|
||||
- `lt` - less than
|
||||
- `lte` - less than or equal
|
||||
- `gt` - greater than
|
||||
- `gte` - greater than or equal
|
||||
| Filter | Description |
|
||||
|--------|-------------|
|
||||
| `n` | Not equal to |
|
||||
| `lt` | Less than |
|
||||
| `lte` | Less than or equal to |
|
||||
| `gt` | Greater than |
|
||||
| `gte` | Greater than or equal to |
|
||||
|
||||
### String Fields
|
||||
|
||||
String based (char) fields (Name, Address, etc) support these lookup expressions:
|
||||
|
||||
- `n` - not equal to (negation)
|
||||
- `ic` - case insensitive contains
|
||||
- `nic` - negated case insensitive contains
|
||||
- `isw` - case insensitive starts with
|
||||
- `nisw` - negated case insensitive starts with
|
||||
- `iew` - case insensitive ends with
|
||||
- `niew` - negated case insensitive ends with
|
||||
- `ie` - case insensitive exact match
|
||||
- `nie` - negated case insensitive exact match
|
||||
| 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) |
|
||||
|
||||
### Foreign Keys & Other Fields
|
||||
|
||||
|
@ -5,4 +5,5 @@ class ExtrasConfig(AppConfig):
|
||||
name = "extras"
|
||||
|
||||
def ready(self):
|
||||
import extras.lookups
|
||||
import extras.signals
|
||||
|
17
netbox/extras/lookups.py
Normal file
17
netbox/extras/lookups.py
Normal file
@ -0,0 +1,17 @@
|
||||
from django.db.models import CharField, Lookup
|
||||
|
||||
|
||||
class Empty(Lookup):
|
||||
"""
|
||||
Filter on whether a string is empty.
|
||||
"""
|
||||
lookup_name = 'empty'
|
||||
|
||||
def as_sql(self, qn, connection):
|
||||
lhs, lhs_params = self.process_lhs(qn, connection)
|
||||
rhs, rhs_params = self.process_rhs(qn, connection)
|
||||
params = lhs_params + rhs_params
|
||||
return 'CAST(LENGTH(%s) AS BOOLEAN) != %s' % (lhs, rhs), params
|
||||
|
||||
|
||||
CharField.register_lookup(Empty)
|
@ -89,13 +89,13 @@ class BaseFilterSet(django_filters.FilterSet):
|
||||
filters.MultiValueNumberFilter,
|
||||
filters.MultiValueTimeFilter
|
||||
)):
|
||||
lookup_map = FILTER_NUMERIC_BASED_LOOKUP_MAP
|
||||
return FILTER_NUMERIC_BASED_LOOKUP_MAP
|
||||
|
||||
elif isinstance(existing_filter, (
|
||||
filters.TreeNodeMultipleChoiceFilter,
|
||||
)):
|
||||
# TreeNodeMultipleChoiceFilter only support negation but must maintain the `in` lookup expression
|
||||
lookup_map = FILTER_TREENODE_NEGATION_LOOKUP_MAP
|
||||
return FILTER_TREENODE_NEGATION_LOOKUP_MAP
|
||||
|
||||
elif isinstance(existing_filter, (
|
||||
django_filters.ModelChoiceFilter,
|
||||
@ -103,7 +103,7 @@ class BaseFilterSet(django_filters.FilterSet):
|
||||
TagFilter
|
||||
)) or existing_filter.extra.get('choices'):
|
||||
# These filter types support only negation
|
||||
lookup_map = FILTER_NEGATION_LOOKUP_MAP
|
||||
return FILTER_NEGATION_LOOKUP_MAP
|
||||
|
||||
elif isinstance(existing_filter, (
|
||||
django_filters.filters.CharFilter,
|
||||
@ -111,12 +111,9 @@ class BaseFilterSet(django_filters.FilterSet):
|
||||
filters.MultiValueCharFilter,
|
||||
filters.MultiValueMACAddressFilter
|
||||
)):
|
||||
lookup_map = FILTER_CHAR_BASED_LOOKUP_MAP
|
||||
return FILTER_CHAR_BASED_LOOKUP_MAP
|
||||
|
||||
else:
|
||||
lookup_map = None
|
||||
|
||||
return lookup_map
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_filters(cls):
|
||||
|
@ -11,7 +11,8 @@ FILTER_CHAR_BASED_LOOKUP_MAP = dict(
|
||||
isw='istartswith',
|
||||
nisw='istartswith',
|
||||
ie='iexact',
|
||||
nie='iexact'
|
||||
nie='iexact',
|
||||
empty='empty',
|
||||
)
|
||||
|
||||
FILTER_NUMERIC_BASED_LOOKUP_MAP = dict(
|
||||
|
Reference in New Issue
Block a user