1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Proof of concept for showing containing prefixes when searching for ip-addresses.

This commit is contained in:
kkthxbye-code
2023-02-06 14:00:34 +01:00
committed by Jeremy Stretch
parent 315371bf7c
commit ce166b12ce
3 changed files with 36 additions and 9 deletions

View File

@ -1,4 +1,4 @@
from django.db.models import CharField, Lookup
from django.db.models import CharField, TextField, Lookup
class Empty(Lookup):
@ -14,4 +14,17 @@ class Empty(Lookup):
return 'CAST(LENGTH(%s) AS BOOLEAN) != %s' % (lhs, rhs), params
class NetContainsOrEquals(Lookup):
"""
This lookup has the same functionality as the one from the ipam app except lhs is cast to inet
"""
lookup_name = 'net_contains_or_equals'
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(%s as inet) >>= %s' % (lhs, rhs), params
CharField.register_lookup(Empty)
TextField.register_lookup(NetContainsOrEquals)

View File

@ -2,6 +2,7 @@ from collections import namedtuple
from django.db import models
from ipam.fields import IPAddressField, IPNetworkField
from netbox.registry import registry
ObjectFieldValue = namedtuple('ObjectFieldValue', ('name', 'type', 'weight', 'value'))
@ -11,6 +12,8 @@ class FieldTypes:
FLOAT = 'float'
INTEGER = 'int'
STRING = 'str'
INET = 'inet'
CIDR = 'cidr'
class LookupTypes:
@ -43,6 +46,10 @@ class SearchIndex:
field_cls = instance._meta.get_field(field_name).__class__
if issubclass(field_cls, (models.FloatField, models.DecimalField)):
return FieldTypes.FLOAT
if issubclass(field_cls, IPAddressField):
return FieldTypes.INET
if issubclass(field_cls, (IPNetworkField)):
return FieldTypes.CIDR
if issubclass(field_cls, models.IntegerField):
return FieldTypes.INTEGER
return FieldTypes.STRING

View File

@ -3,10 +3,12 @@ from collections import defaultdict
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured
from django.db.models import F, Window
from django.db.models import F, Window, Q
from django.db.models.functions import window
from django.db.models.signals import post_delete, post_save
from django.utils.module_loading import import_string
import netaddr
from netaddr.core import AddrFormatError
from extras.models import CachedValue, CustomField
from netbox.registry import registry
@ -95,18 +97,23 @@ class CachedValueSearchBackend(SearchBackend):
def search(self, value, user=None, object_types=None, lookup=DEFAULT_LOOKUP_TYPE):
# Define the search parameters
params = {
f'value__{lookup}': value
}
query_filter = Q(**{f'value__{lookup}': value})
if lookup in (LookupTypes.STARTSWITH, LookupTypes.ENDSWITH):
# Partial string matches are valid only on string values
params['type'] = FieldTypes.STRING
query_filter &= Q(type=FieldTypes.STRING)
if object_types:
params['object_type__in'] = object_types
query_filter &= Q(object_typeo__in=object_types)
if lookup == LookupTypes.PARTIAL:
try:
address = str(netaddr.IPNetwork(value.strip()).cidr)
query_filter |= Q(type=FieldTypes.CIDR) & Q(value__net_contains_or_equals=address)
except (AddrFormatError, ValueError):
pass
# Construct the base queryset to retrieve matching results
queryset = CachedValue.objects.filter(**params).annotate(
queryset = CachedValue.objects.filter(query_filter).annotate(
# Annotate the rank of each result for its object according to its weight
row_number=Window(
expression=window.RowNumber(),