mirror of
				https://github.com/netbox-community/netbox.git
				synced 2024-05-10 07:54:54 +00:00 
			
		
		
		
	Merge pull request #8573 from 991jo/asn_search_fix
Fixes 8553: Fix contacts and ASNs missing in the search dropdown and …
This commit is contained in:
		@@ -1,4 +1,5 @@
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
from typing import Dict
 | 
			
		||||
 | 
			
		||||
from circuits.filtersets import CircuitFilterSet, ProviderFilterSet, ProviderNetworkFilterSet
 | 
			
		||||
from circuits.models import Circuit, ProviderNetwork, Provider
 | 
			
		||||
@@ -26,169 +27,212 @@ from virtualization.models import Cluster, VirtualMachine
 | 
			
		||||
from virtualization.tables import ClusterTable, VirtualMachineTable
 | 
			
		||||
 | 
			
		||||
SEARCH_MAX_RESULTS = 15
 | 
			
		||||
SEARCH_TYPES = OrderedDict((
 | 
			
		||||
    # Circuits
 | 
			
		||||
    ('provider', {
 | 
			
		||||
        'queryset': Provider.objects.annotate(
 | 
			
		||||
            count_circuits=count_related(Circuit, 'provider')
 | 
			
		||||
        ),
 | 
			
		||||
        'filterset': ProviderFilterSet,
 | 
			
		||||
        'table': ProviderTable,
 | 
			
		||||
        'url': 'circuits:provider_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('circuit', {
 | 
			
		||||
        'queryset': Circuit.objects.prefetch_related(
 | 
			
		||||
            'type', 'provider', 'tenant', 'terminations__site'
 | 
			
		||||
        ),
 | 
			
		||||
        'filterset': CircuitFilterSet,
 | 
			
		||||
        'table': CircuitTable,
 | 
			
		||||
        'url': 'circuits:circuit_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('providernetwork', {
 | 
			
		||||
        'queryset': ProviderNetwork.objects.prefetch_related('provider'),
 | 
			
		||||
        'filterset': ProviderNetworkFilterSet,
 | 
			
		||||
        'table': ProviderNetworkTable,
 | 
			
		||||
        'url': 'circuits:providernetwork_list',
 | 
			
		||||
    }),
 | 
			
		||||
    # DCIM
 | 
			
		||||
    ('site', {
 | 
			
		||||
        'queryset': Site.objects.prefetch_related('region', 'tenant'),
 | 
			
		||||
        'filterset': SiteFilterSet,
 | 
			
		||||
        'table': SiteTable,
 | 
			
		||||
        'url': 'dcim:site_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('rack', {
 | 
			
		||||
        'queryset': Rack.objects.prefetch_related('site', 'location', 'tenant', 'role'),
 | 
			
		||||
        'filterset': RackFilterSet,
 | 
			
		||||
        'table': RackTable,
 | 
			
		||||
        'url': 'dcim:rack_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('rackreservation', {
 | 
			
		||||
        'queryset': RackReservation.objects.prefetch_related('site', 'rack', 'user'),
 | 
			
		||||
        'filterset': RackReservationFilterSet,
 | 
			
		||||
        'table': RackReservationTable,
 | 
			
		||||
        'url': 'dcim:rackreservation_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('location', {
 | 
			
		||||
        'queryset': Location.objects.add_related_count(
 | 
			
		||||
            Location.objects.add_related_count(
 | 
			
		||||
                Location.objects.all(),
 | 
			
		||||
                Device,
 | 
			
		||||
                'location',
 | 
			
		||||
                'device_count',
 | 
			
		||||
                cumulative=True
 | 
			
		||||
 | 
			
		||||
CIRCUIT_TYPES = OrderedDict(
 | 
			
		||||
    (
 | 
			
		||||
        ('provider', {
 | 
			
		||||
            'queryset': Provider.objects.annotate(
 | 
			
		||||
                count_circuits=count_related(Circuit, 'provider')
 | 
			
		||||
            ),
 | 
			
		||||
            Rack,
 | 
			
		||||
            'location',
 | 
			
		||||
            'rack_count',
 | 
			
		||||
            cumulative=True
 | 
			
		||||
        ).prefetch_related('site'),
 | 
			
		||||
        'filterset': LocationFilterSet,
 | 
			
		||||
        'table': LocationTable,
 | 
			
		||||
        'url': 'dcim:location_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('devicetype', {
 | 
			
		||||
        'queryset': DeviceType.objects.prefetch_related('manufacturer').annotate(
 | 
			
		||||
            instance_count=count_related(Device, 'device_type')
 | 
			
		||||
        ),
 | 
			
		||||
        'filterset': DeviceTypeFilterSet,
 | 
			
		||||
        'table': DeviceTypeTable,
 | 
			
		||||
        'url': 'dcim:devicetype_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('device', {
 | 
			
		||||
        'queryset': Device.objects.prefetch_related(
 | 
			
		||||
            'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6',
 | 
			
		||||
        ),
 | 
			
		||||
        'filterset': DeviceFilterSet,
 | 
			
		||||
        'table': DeviceTable,
 | 
			
		||||
        'url': 'dcim:device_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('virtualchassis', {
 | 
			
		||||
        'queryset': VirtualChassis.objects.prefetch_related('master').annotate(
 | 
			
		||||
            member_count=count_related(Device, 'virtual_chassis')
 | 
			
		||||
        ),
 | 
			
		||||
        'filterset': VirtualChassisFilterSet,
 | 
			
		||||
        'table': VirtualChassisTable,
 | 
			
		||||
        'url': 'dcim:virtualchassis_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('cable', {
 | 
			
		||||
        'queryset': Cable.objects.all(),
 | 
			
		||||
        'filterset': CableFilterSet,
 | 
			
		||||
        'table': CableTable,
 | 
			
		||||
        'url': 'dcim:cable_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('powerfeed', {
 | 
			
		||||
        'queryset': PowerFeed.objects.all(),
 | 
			
		||||
        'filterset': PowerFeedFilterSet,
 | 
			
		||||
        'table': PowerFeedTable,
 | 
			
		||||
        'url': 'dcim:powerfeed_list',
 | 
			
		||||
    }),
 | 
			
		||||
    # Virtualization
 | 
			
		||||
    ('cluster', {
 | 
			
		||||
        'queryset': Cluster.objects.prefetch_related('type', 'group').annotate(
 | 
			
		||||
            device_count=count_related(Device, 'cluster'),
 | 
			
		||||
            vm_count=count_related(VirtualMachine, 'cluster')
 | 
			
		||||
        ),
 | 
			
		||||
        'filterset': ClusterFilterSet,
 | 
			
		||||
        'table': ClusterTable,
 | 
			
		||||
        'url': 'virtualization:cluster_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('virtualmachine', {
 | 
			
		||||
        'queryset': VirtualMachine.objects.prefetch_related(
 | 
			
		||||
            'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6',
 | 
			
		||||
        ),
 | 
			
		||||
        'filterset': VirtualMachineFilterSet,
 | 
			
		||||
        'table': VirtualMachineTable,
 | 
			
		||||
        'url': 'virtualization:virtualmachine_list',
 | 
			
		||||
    }),
 | 
			
		||||
    # IPAM
 | 
			
		||||
    ('vrf', {
 | 
			
		||||
        'queryset': VRF.objects.prefetch_related('tenant'),
 | 
			
		||||
        'filterset': VRFFilterSet,
 | 
			
		||||
        'table': VRFTable,
 | 
			
		||||
        'url': 'ipam:vrf_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('aggregate', {
 | 
			
		||||
        'queryset': Aggregate.objects.prefetch_related('rir'),
 | 
			
		||||
        'filterset': AggregateFilterSet,
 | 
			
		||||
        'table': AggregateTable,
 | 
			
		||||
        'url': 'ipam:aggregate_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('prefix', {
 | 
			
		||||
        'queryset': Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'),
 | 
			
		||||
        'filterset': PrefixFilterSet,
 | 
			
		||||
        'table': PrefixTable,
 | 
			
		||||
        'url': 'ipam:prefix_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('ipaddress', {
 | 
			
		||||
        'queryset': IPAddress.objects.prefetch_related('vrf__tenant', 'tenant'),
 | 
			
		||||
        'filterset': IPAddressFilterSet,
 | 
			
		||||
        'table': IPAddressTable,
 | 
			
		||||
        'url': 'ipam:ipaddress_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('vlan', {
 | 
			
		||||
        'queryset': VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role'),
 | 
			
		||||
        'filterset': VLANFilterSet,
 | 
			
		||||
        'table': VLANTable,
 | 
			
		||||
        'url': 'ipam:vlan_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('asn', {
 | 
			
		||||
        'queryset': ASN.objects.prefetch_related('rir', 'tenant'),
 | 
			
		||||
        'filterset': ASNFilterSet,
 | 
			
		||||
        'table': ASNTable,
 | 
			
		||||
        'url': 'ipam:asn_list',
 | 
			
		||||
    }),
 | 
			
		||||
    # Tenancy
 | 
			
		||||
    ('tenant', {
 | 
			
		||||
        'queryset': Tenant.objects.prefetch_related('group'),
 | 
			
		||||
        'filterset': TenantFilterSet,
 | 
			
		||||
        'table': TenantTable,
 | 
			
		||||
        'url': 'tenancy:tenant_list',
 | 
			
		||||
    }),
 | 
			
		||||
    ('contact', {
 | 
			
		||||
        'queryset': Contact.objects.prefetch_related('group', 'assignments').annotate(assignment_count=count_related(ContactAssignment, 'contact')),
 | 
			
		||||
        'filterset': ContactFilterSet,
 | 
			
		||||
        'table': ContactTable,
 | 
			
		||||
        'url': 'tenancy:contact_list',
 | 
			
		||||
    }),
 | 
			
		||||
))
 | 
			
		||||
            'filterset': ProviderFilterSet,
 | 
			
		||||
            'table': ProviderTable,
 | 
			
		||||
            'url': 'circuits:provider_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('circuit', {
 | 
			
		||||
            'queryset': Circuit.objects.prefetch_related(
 | 
			
		||||
                'type', 'provider', 'tenant', 'terminations__site'
 | 
			
		||||
            ),
 | 
			
		||||
            'filterset': CircuitFilterSet,
 | 
			
		||||
            'table': CircuitTable,
 | 
			
		||||
            'url': 'circuits:circuit_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('providernetwork', {
 | 
			
		||||
            'queryset': ProviderNetwork.objects.prefetch_related('provider'),
 | 
			
		||||
            'filterset': ProviderNetworkFilterSet,
 | 
			
		||||
            'table': ProviderNetworkTable,
 | 
			
		||||
            'url': 'circuits:providernetwork_list',
 | 
			
		||||
        }),
 | 
			
		||||
    )
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DCIM_TYPES = OrderedDict(
 | 
			
		||||
    (
 | 
			
		||||
        ('site', {
 | 
			
		||||
            'queryset': Site.objects.prefetch_related('region', 'tenant'),
 | 
			
		||||
            'filterset': SiteFilterSet,
 | 
			
		||||
            'table': SiteTable,
 | 
			
		||||
            'url': 'dcim:site_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('rack', {
 | 
			
		||||
            'queryset': Rack.objects.prefetch_related('site', 'location', 'tenant', 'role'),
 | 
			
		||||
            'filterset': RackFilterSet,
 | 
			
		||||
            'table': RackTable,
 | 
			
		||||
            'url': 'dcim:rack_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('rackreservation', {
 | 
			
		||||
            'queryset': RackReservation.objects.prefetch_related('site', 'rack', 'user'),
 | 
			
		||||
            'filterset': RackReservationFilterSet,
 | 
			
		||||
            'table': RackReservationTable,
 | 
			
		||||
            'url': 'dcim:rackreservation_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('location', {
 | 
			
		||||
            'queryset': Location.objects.add_related_count(
 | 
			
		||||
                Location.objects.add_related_count(
 | 
			
		||||
                    Location.objects.all(),
 | 
			
		||||
                    Device,
 | 
			
		||||
                    'location',
 | 
			
		||||
                    'device_count',
 | 
			
		||||
                    cumulative=True
 | 
			
		||||
                ),
 | 
			
		||||
                Rack,
 | 
			
		||||
                'location',
 | 
			
		||||
                'rack_count',
 | 
			
		||||
                cumulative=True
 | 
			
		||||
            ).prefetch_related('site'),
 | 
			
		||||
            'filterset': LocationFilterSet,
 | 
			
		||||
            'table': LocationTable,
 | 
			
		||||
            'url': 'dcim:location_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('devicetype', {
 | 
			
		||||
            'queryset': DeviceType.objects.prefetch_related('manufacturer').annotate(
 | 
			
		||||
                instance_count=count_related(Device, 'device_type')
 | 
			
		||||
            ),
 | 
			
		||||
            'filterset': DeviceTypeFilterSet,
 | 
			
		||||
            'table': DeviceTypeTable,
 | 
			
		||||
            'url': 'dcim:devicetype_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('device', {
 | 
			
		||||
            'queryset': Device.objects.prefetch_related(
 | 
			
		||||
                'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6',
 | 
			
		||||
            ),
 | 
			
		||||
            'filterset': DeviceFilterSet,
 | 
			
		||||
            'table': DeviceTable,
 | 
			
		||||
            'url': 'dcim:device_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('virtualchassis', {
 | 
			
		||||
            'queryset': VirtualChassis.objects.prefetch_related('master').annotate(
 | 
			
		||||
                member_count=count_related(Device, 'virtual_chassis')
 | 
			
		||||
            ),
 | 
			
		||||
            'filterset': VirtualChassisFilterSet,
 | 
			
		||||
            'table': VirtualChassisTable,
 | 
			
		||||
            'url': 'dcim:virtualchassis_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('cable', {
 | 
			
		||||
            'queryset': Cable.objects.all(),
 | 
			
		||||
            'filterset': CableFilterSet,
 | 
			
		||||
            'table': CableTable,
 | 
			
		||||
            'url': 'dcim:cable_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('powerfeed', {
 | 
			
		||||
            'queryset': PowerFeed.objects.all(),
 | 
			
		||||
            'filterset': PowerFeedFilterSet,
 | 
			
		||||
            'table': PowerFeedTable,
 | 
			
		||||
            'url': 'dcim:powerfeed_list',
 | 
			
		||||
        }),
 | 
			
		||||
    )
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
IPAM_TYPES = OrderedDict(
 | 
			
		||||
    (
 | 
			
		||||
        ('vrf', {
 | 
			
		||||
            'queryset': VRF.objects.prefetch_related('tenant'),
 | 
			
		||||
            'filterset': VRFFilterSet,
 | 
			
		||||
            'table': VRFTable,
 | 
			
		||||
            'url': 'ipam:vrf_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('aggregate', {
 | 
			
		||||
            'queryset': Aggregate.objects.prefetch_related('rir'),
 | 
			
		||||
            'filterset': AggregateFilterSet,
 | 
			
		||||
            'table': AggregateTable,
 | 
			
		||||
            'url': 'ipam:aggregate_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('prefix', {
 | 
			
		||||
            'queryset': Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'),
 | 
			
		||||
            'filterset': PrefixFilterSet,
 | 
			
		||||
            'table': PrefixTable,
 | 
			
		||||
            'url': 'ipam:prefix_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('ipaddress', {
 | 
			
		||||
            'queryset': IPAddress.objects.prefetch_related('vrf__tenant', 'tenant'),
 | 
			
		||||
            'filterset': IPAddressFilterSet,
 | 
			
		||||
            'table': IPAddressTable,
 | 
			
		||||
            'url': 'ipam:ipaddress_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('vlan', {
 | 
			
		||||
            'queryset': VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role'),
 | 
			
		||||
            'filterset': VLANFilterSet,
 | 
			
		||||
            'table': VLANTable,
 | 
			
		||||
            'url': 'ipam:vlan_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('asn', {
 | 
			
		||||
            'queryset': ASN.objects.prefetch_related('rir', 'tenant'),
 | 
			
		||||
            'filterset': ASNFilterSet,
 | 
			
		||||
            'table': ASNTable,
 | 
			
		||||
            'url': 'ipam:asn_list',
 | 
			
		||||
        }),
 | 
			
		||||
    )
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
TENANCY_TYPES = OrderedDict(
 | 
			
		||||
    (
 | 
			
		||||
        ('tenant', {
 | 
			
		||||
            'queryset': Tenant.objects.prefetch_related('group'),
 | 
			
		||||
            'filterset': TenantFilterSet,
 | 
			
		||||
            'table': TenantTable,
 | 
			
		||||
            'url': 'tenancy:tenant_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('contact', {
 | 
			
		||||
            'queryset': Contact.objects.prefetch_related('group', 'assignments').annotate(
 | 
			
		||||
                assignment_count=count_related(ContactAssignment, 'contact')),
 | 
			
		||||
            'filterset': ContactFilterSet,
 | 
			
		||||
            'table': ContactTable,
 | 
			
		||||
            'url': 'tenancy:contact_list',
 | 
			
		||||
        }),
 | 
			
		||||
    )
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
VIRTUALIZATION_TYPES = OrderedDict(
 | 
			
		||||
    (
 | 
			
		||||
        ('cluster', {
 | 
			
		||||
            'queryset': Cluster.objects.prefetch_related('type', 'group').annotate(
 | 
			
		||||
                device_count=count_related(Device, 'cluster'),
 | 
			
		||||
                vm_count=count_related(VirtualMachine, 'cluster')
 | 
			
		||||
            ),
 | 
			
		||||
            'filterset': ClusterFilterSet,
 | 
			
		||||
            'table': ClusterTable,
 | 
			
		||||
            'url': 'virtualization:cluster_list',
 | 
			
		||||
        }),
 | 
			
		||||
        ('virtualmachine', {
 | 
			
		||||
            'queryset': VirtualMachine.objects.prefetch_related(
 | 
			
		||||
                'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6',
 | 
			
		||||
            ),
 | 
			
		||||
            'filterset': VirtualMachineFilterSet,
 | 
			
		||||
            'table': VirtualMachineTable,
 | 
			
		||||
            'url': 'virtualization:virtualmachine_list',
 | 
			
		||||
        }),
 | 
			
		||||
    )
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
SEARCH_TYPE_HIERARCHY = OrderedDict(
 | 
			
		||||
    (
 | 
			
		||||
        ("Circuits", CIRCUIT_TYPES),
 | 
			
		||||
        ("DCIM", DCIM_TYPES),
 | 
			
		||||
        ("IPAM", IPAM_TYPES),
 | 
			
		||||
        ("Tenancy", TENANCY_TYPES),
 | 
			
		||||
        ("Virtualization", VIRTUALIZATION_TYPES),
 | 
			
		||||
    )
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_search_types() -> Dict[str, Dict]:
 | 
			
		||||
    result = dict()
 | 
			
		||||
 | 
			
		||||
    for app_types in SEARCH_TYPE_HIERARCHY.values():
 | 
			
		||||
        for name, items in app_types.items():
 | 
			
		||||
            result[name] = items
 | 
			
		||||
 | 
			
		||||
    return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SEARCH_TYPES = build_search_types()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,39 +1,24 @@
 | 
			
		||||
from django import forms
 | 
			
		||||
 | 
			
		||||
from utilities.forms import BootstrapMixin
 | 
			
		||||
from netbox.constants import SEARCH_TYPE_HIERARCHY
 | 
			
		||||
 | 
			
		||||
OBJ_TYPE_CHOICES = (
 | 
			
		||||
    ('', 'All Objects'),
 | 
			
		||||
    ('Circuits', (
 | 
			
		||||
        ('provider', 'Providers'),
 | 
			
		||||
        ('circuit', 'Circuits'),
 | 
			
		||||
    )),
 | 
			
		||||
    ('DCIM', (
 | 
			
		||||
        ('site', 'Sites'),
 | 
			
		||||
        ('rack', 'Racks'),
 | 
			
		||||
        ('rackreservation', 'Rack reservations'),
 | 
			
		||||
        ('location', 'Locations'),
 | 
			
		||||
        ('devicetype', 'Device Types'),
 | 
			
		||||
        ('device', 'Devices'),
 | 
			
		||||
        ('virtualchassis', 'Virtual chassis'),
 | 
			
		||||
        ('cable', 'Cables'),
 | 
			
		||||
        ('powerfeed', 'Power feeds'),
 | 
			
		||||
    )),
 | 
			
		||||
    ('IPAM', (
 | 
			
		||||
        ('vrf', 'VRFs'),
 | 
			
		||||
        ('aggregate', 'Aggregates'),
 | 
			
		||||
        ('prefix', 'Prefixes'),
 | 
			
		||||
        ('ipaddress', 'IP Addresses'),
 | 
			
		||||
        ('vlan', 'VLANs'),
 | 
			
		||||
    )),
 | 
			
		||||
    ('Tenancy', (
 | 
			
		||||
        ('tenant', 'Tenants'),
 | 
			
		||||
    )),
 | 
			
		||||
    ('Virtualization', (
 | 
			
		||||
        ('cluster', 'Clusters'),
 | 
			
		||||
        ('virtualmachine', 'Virtual Machines'),
 | 
			
		||||
    )),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
def build_search_choices():
 | 
			
		||||
    result = list()
 | 
			
		||||
    result.append(('', 'All Objects'))
 | 
			
		||||
    for category, items in SEARCH_TYPE_HIERARCHY.items():
 | 
			
		||||
        subcategories = list()
 | 
			
		||||
        for slug, obj in items.items():
 | 
			
		||||
            name = obj['queryset'].model._meta.verbose_name_plural
 | 
			
		||||
            name = name[0].upper() + name[1:]
 | 
			
		||||
            subcategories.append((slug, name))
 | 
			
		||||
        result.append((category, tuple(subcategories)))
 | 
			
		||||
 | 
			
		||||
    return tuple(result)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
OBJ_TYPE_CHOICES = build_search_choices()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_options():
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user