We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add Primary IP for a device to Search Results
<!--
    Before opening a new issue, please search through the existing issues to
    see if your topic has already been addressed. Note that you may need to
    remove the "is:open" filter from the search bar to include closed issues.

    Check the appropriate type for your issue below by placing an x between the
    brackets. If none of the below apply, please raise your issue for
    discussion on our mailing list:

        https://groups.google.com/forum/#!forum/netbox-discuss

    Please note that issues which do not fall under any of the below categories
    will be closed.
--->
### Issue type
[X] Feature request <!-- Requesting the implementation of a new feature -->

<!--
    Please describe the environment in which you are running NetBox. (Be sure
    to verify that you are running the latest stable release of NetBox before
    submitting a bug report.)
-->
### Environment
* Python version:  2.7.5
* NetBox version:  2.1.4

<!--
    BUG REPORTS must include:
        * A list of the steps needed to reproduce the bug
        * A description of the expected behavior
        * Any relevant error messages (screenshots may also help)

    FEATURE REQUESTS must include:
        * A detailed description of the proposed functionality
        * A use case for the new feature
        * A rough description of any necessary changes to the database schema
        * Any relevant third-party libraries which would be needed
-->
### Description
When searching for a device name from the upper-right search box please add the Primary IP (if assigned) to the results.  Currently the Device results include these fields:  Name, Status, Tenant, Site, Rack, Role, Type

This is an example of the URL for this search: https://netbox/search/?q=SW

Use case is, given a name, find the IP as quickly as possible. 

No DB changes or additional libraries should be needed.





--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `netbox/netbox/views.py`
Content:
```
1 from __future__ import unicode_literals
2 from collections import OrderedDict
3 import sys
4 
5 from rest_framework.views import APIView
6 from rest_framework.response import Response
7 from rest_framework.reverse import reverse
8 
9 from django.shortcuts import render
10 from django.views.generic import View
11 
12 from circuits.filters import CircuitFilter, ProviderFilter
13 from circuits.models import Circuit, Provider
14 from circuits.tables import CircuitTable, ProviderTable
15 from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter
16 from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site
17 from dcim.tables import DeviceTable, DeviceTypeTable, RackTable, SiteTable
18 from extras.models import TopologyMap, UserAction
19 from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter
20 from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF
21 from ipam.tables import AggregateTable, IPAddressTable, PrefixTable, VLANTable, VRFTable
22 from secrets.filters import SecretFilter
23 from secrets.models import Secret
24 from secrets.tables import SecretTable
25 from tenancy.filters import TenantFilter
26 from tenancy.models import Tenant
27 from tenancy.tables import TenantTable
28 from .forms import SearchForm
29 
30 
31 SEARCH_MAX_RESULTS = 15
32 SEARCH_TYPES = OrderedDict((
33     # Circuits
34     ('provider', {
35         'queryset': Provider.objects.all(),
36         'filter': ProviderFilter,
37         'table': ProviderTable,
38         'url': 'circuits:provider_list',
39     }),
40     ('circuit', {
41         'queryset': Circuit.objects.select_related('type', 'provider', 'tenant').prefetch_related('terminations__site'),
42         'filter': CircuitFilter,
43         'table': CircuitTable,
44         'url': 'circuits:circuit_list',
45     }),
46     # DCIM
47     ('site', {
48         'queryset': Site.objects.select_related('region', 'tenant'),
49         'filter': SiteFilter,
50         'table': SiteTable,
51         'url': 'dcim:site_list',
52     }),
53     ('rack', {
54         'queryset': Rack.objects.select_related('site', 'group', 'tenant', 'role'),
55         'filter': RackFilter,
56         'table': RackTable,
57         'url': 'dcim:rack_list',
58     }),
59     ('devicetype', {
60         'queryset': DeviceType.objects.select_related('manufacturer'),
61         'filter': DeviceTypeFilter,
62         'table': DeviceTypeTable,
63         'url': 'dcim:devicetype_list',
64     }),
65     ('device', {
66         'queryset': Device.objects.select_related(
67             'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack'
68         ),
69         'filter': DeviceFilter,
70         'table': DeviceTable,
71         'url': 'dcim:device_list',
72     }),
73     # IPAM
74     ('vrf', {
75         'queryset': VRF.objects.select_related('tenant'),
76         'filter': VRFFilter,
77         'table': VRFTable,
78         'url': 'ipam:vrf_list',
79     }),
80     ('aggregate', {
81         'queryset': Aggregate.objects.select_related('rir'),
82         'filter': AggregateFilter,
83         'table': AggregateTable,
84         'url': 'ipam:aggregate_list',
85     }),
86     ('prefix', {
87         'queryset': Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'),
88         'filter': PrefixFilter,
89         'table': PrefixTable,
90         'url': 'ipam:prefix_list',
91     }),
92     ('ipaddress', {
93         'queryset': IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device'),
94         'filter': IPAddressFilter,
95         'table': IPAddressTable,
96         'url': 'ipam:ipaddress_list',
97     }),
98     ('vlan', {
99         'queryset': VLAN.objects.select_related('site', 'group', 'tenant', 'role'),
100         'filter': VLANFilter,
101         'table': VLANTable,
102         'url': 'ipam:vlan_list',
103     }),
104     # Secrets
105     ('secret', {
106         'queryset': Secret.objects.select_related('role', 'device'),
107         'filter': SecretFilter,
108         'table': SecretTable,
109         'url': 'secrets:secret_list',
110     }),
111     # Tenancy
112     ('tenant', {
113         'queryset': Tenant.objects.select_related('group'),
114         'filter': TenantFilter,
115         'table': TenantTable,
116         'url': 'tenancy:tenant_list',
117     }),
118 ))
119 
120 
121 class HomeView(View):
122     template_name = 'home.html'
123 
124     def get(self, request):
125 
126         stats = {
127 
128             # Organization
129             'site_count': Site.objects.count(),
130             'tenant_count': Tenant.objects.count(),
131 
132             # DCIM
133             'rack_count': Rack.objects.count(),
134             'device_count': Device.objects.count(),
135             'interface_connections_count': InterfaceConnection.objects.count(),
136             'console_connections_count': ConsolePort.objects.filter(cs_port__isnull=False).count(),
137             'power_connections_count': PowerPort.objects.filter(power_outlet__isnull=False).count(),
138 
139             # IPAM
140             'vrf_count': VRF.objects.count(),
141             'aggregate_count': Aggregate.objects.count(),
142             'prefix_count': Prefix.objects.count(),
143             'ipaddress_count': IPAddress.objects.count(),
144             'vlan_count': VLAN.objects.count(),
145 
146             # Circuits
147             'provider_count': Provider.objects.count(),
148             'circuit_count': Circuit.objects.count(),
149 
150             # Secrets
151             'secret_count': Secret.objects.count(),
152 
153         }
154 
155         return render(request, self.template_name, {
156             'search_form': SearchForm(),
157             'stats': stats,
158             'topology_maps': TopologyMap.objects.filter(site__isnull=True),
159             'recent_activity': UserAction.objects.select_related('user')[:50]
160         })
161 
162 
163 class SearchView(View):
164 
165     def get(self, request):
166 
167         # No query
168         if 'q' not in request.GET:
169             return render(request, 'search.html', {
170                 'form': SearchForm(),
171             })
172 
173         form = SearchForm(request.GET)
174         results = []
175 
176         if form.is_valid():
177 
178             # Searching for a single type of object
179             if form.cleaned_data['obj_type']:
180                 obj_types = [form.cleaned_data['obj_type']]
181             # Searching all object types
182             else:
183                 obj_types = SEARCH_TYPES.keys()
184 
185             for obj_type in obj_types:
186 
187                 queryset = SEARCH_TYPES[obj_type]['queryset']
188                 filter_cls = SEARCH_TYPES[obj_type]['filter']
189                 table = SEARCH_TYPES[obj_type]['table']
190                 url = SEARCH_TYPES[obj_type]['url']
191 
192                 # Construct the results table for this object type
193                 filtered_queryset = filter_cls({'q': form.cleaned_data['q']}, queryset=queryset).qs
194                 table = table(filtered_queryset, orderable=False)
195                 table.paginate(per_page=SEARCH_MAX_RESULTS)
196 
197                 if table.page:
198                     results.append({
199                         'name': queryset.model._meta.verbose_name_plural,
200                         'table': table,
201                         'url': '{}?q={}'.format(reverse(url), form.cleaned_data['q'])
202                     })
203 
204         return render(request, 'search.html', {
205             'form': form,
206             'results': results,
207         })
208 
209 
210 class APIRootView(APIView):
211     _ignore_model_permissions = True
212     exclude_from_schema = True
213 
214     def get_view_name(self):
215         return "API Root"
216 
217     def get(self, request, format=None):
218 
219         return Response({
220             'circuits': reverse('circuits-api:api-root', request=request, format=format),
221             'dcim': reverse('dcim-api:api-root', request=request, format=format),
222             'extras': reverse('extras-api:api-root', request=request, format=format),
223             'ipam': reverse('ipam-api:api-root', request=request, format=format),
224             'secrets': reverse('secrets-api:api-root', request=request, format=format),
225             'tenancy': reverse('tenancy-api:api-root', request=request, format=format),
226         })
227 
228 
229 def handle_500(request):
230     """
231     Custom server error handler
232     """
233     type_, error, traceback = sys.exc_info()
234     return render(request, '500.html', {
235         'exception': str(type_),
236         'error': error,
237     }, status=500)
238 
239 
240 def trigger_500(request):
241     """
242     Hot-wired method of triggering a server error to test reporting
243     """
244     raise Exception(
245         "Congratulations, you've triggered an exception! Go tell all your friends what an exceptional person you are."
246     )
247
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py
--- a/netbox/netbox/views.py
+++ b/netbox/netbox/views.py
@@ -14,7 +14,7 @@
 from circuits.tables import CircuitTable, ProviderTable
 from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter
 from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site
-from dcim.tables import DeviceTable, DeviceTypeTable, RackTable, SiteTable
+from dcim.tables import DeviceDetailTable, DeviceTypeTable, RackTable, SiteTable
 from extras.models import TopologyMap, UserAction
 from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter
 from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF
@@ -67,7 +67,7 @@
             'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack'
         ),
         'filter': DeviceFilter,
-        'table': DeviceTable,
+        'table': DeviceDetailTable,
         'url': 'dcim:device_list',
     }),
     # IPAM

{"golden_diff": "diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py\n--- a/netbox/netbox/views.py\n+++ b/netbox/netbox/views.py\n@@ -14,7 +14,7 @@\n from circuits.tables import CircuitTable, ProviderTable\n from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter\n from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site\n-from dcim.tables import DeviceTable, DeviceTypeTable, RackTable, SiteTable\n+from dcim.tables import DeviceDetailTable, DeviceTypeTable, RackTable, SiteTable\n from extras.models import TopologyMap, UserAction\n from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter\n from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF\n@@ -67,7 +67,7 @@\n             'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack'\n         ),\n         'filter': DeviceFilter,\n-        'table': DeviceTable,\n+        'table': DeviceDetailTable,\n         'url': 'dcim:device_list',\n     }),\n     # IPAM\n", "issue": "Add Primary IP for a device to Search Results\n<!--\r\n    Before opening a new issue, please search through the existing issues to\r\n    see if your topic has already been addressed. Note that you may need to\r\n    remove the \"is:open\" filter from the search bar to include closed issues.\r\n\r\n    Check the appropriate type for your issue below by placing an x between the\r\n    brackets. If none of the below apply, please raise your issue for\r\n    discussion on our mailing list:\r\n\r\n        https://groups.google.com/forum/#!forum/netbox-discuss\r\n\r\n    Please note that issues which do not fall under any of the below categories\r\n    will be closed.\r\n--->\r\n### Issue type\r\n[X] Feature request <!-- Requesting the implementation of a new feature -->\r\n\r\n<!--\r\n    Please describe the environment in which you are running NetBox. (Be sure\r\n    to verify that you are running the latest stable release of NetBox before\r\n    submitting a bug report.)\r\n-->\r\n### Environment\r\n* Python version:  2.7.5\r\n* NetBox version:  2.1.4\r\n\r\n<!--\r\n    BUG REPORTS must include:\r\n        * A list of the steps needed to reproduce the bug\r\n        * A description of the expected behavior\r\n        * Any relevant error messages (screenshots may also help)\r\n\r\n    FEATURE REQUESTS must include:\r\n        * A detailed description of the proposed functionality\r\n        * A use case for the new feature\r\n        * A rough description of any necessary changes to the database schema\r\n        * Any relevant third-party libraries which would be needed\r\n-->\r\n### Description\r\nWhen searching for a device name from the upper-right search box please add the Primary IP (if assigned) to the results.  Currently the Device results include these fields:  Name, Status, Tenant, Site, Rack, Role, Type\r\n\r\nThis is an example of the URL for this search: https://netbox/search/?q=SW\r\n\r\nUse case is, given a name, find the IP as quickly as possible. \r\n\r\nNo DB changes or additional libraries should be needed.\r\n\r\n\r\n\r\n\n", "before_files": [{"content": "from __future__ import unicode_literals\nfrom collections import OrderedDict\nimport sys\n\nfrom rest_framework.views import APIView\nfrom rest_framework.response import Response\nfrom rest_framework.reverse import reverse\n\nfrom django.shortcuts import render\nfrom django.views.generic import View\n\nfrom circuits.filters import CircuitFilter, ProviderFilter\nfrom circuits.models import Circuit, Provider\nfrom circuits.tables import CircuitTable, ProviderTable\nfrom dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter\nfrom dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site\nfrom dcim.tables import DeviceTable, DeviceTypeTable, RackTable, SiteTable\nfrom extras.models import TopologyMap, UserAction\nfrom ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter\nfrom ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF\nfrom ipam.tables import AggregateTable, IPAddressTable, PrefixTable, VLANTable, VRFTable\nfrom secrets.filters import SecretFilter\nfrom secrets.models import Secret\nfrom secrets.tables import SecretTable\nfrom tenancy.filters import TenantFilter\nfrom tenancy.models import Tenant\nfrom tenancy.tables import TenantTable\nfrom .forms import SearchForm\n\n\nSEARCH_MAX_RESULTS = 15\nSEARCH_TYPES = OrderedDict((\n    # Circuits\n    ('provider', {\n        'queryset': Provider.objects.all(),\n        'filter': ProviderFilter,\n        'table': ProviderTable,\n        'url': 'circuits:provider_list',\n    }),\n    ('circuit', {\n        'queryset': Circuit.objects.select_related('type', 'provider', 'tenant').prefetch_related('terminations__site'),\n        'filter': CircuitFilter,\n        'table': CircuitTable,\n        'url': 'circuits:circuit_list',\n    }),\n    # DCIM\n    ('site', {\n        'queryset': Site.objects.select_related('region', 'tenant'),\n        'filter': SiteFilter,\n        'table': SiteTable,\n        'url': 'dcim:site_list',\n    }),\n    ('rack', {\n        'queryset': Rack.objects.select_related('site', 'group', 'tenant', 'role'),\n        'filter': RackFilter,\n        'table': RackTable,\n        'url': 'dcim:rack_list',\n    }),\n    ('devicetype', {\n        'queryset': DeviceType.objects.select_related('manufacturer'),\n        'filter': DeviceTypeFilter,\n        'table': DeviceTypeTable,\n        'url': 'dcim:devicetype_list',\n    }),\n    ('device', {\n        'queryset': Device.objects.select_related(\n            'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack'\n        ),\n        'filter': DeviceFilter,\n        'table': DeviceTable,\n        'url': 'dcim:device_list',\n    }),\n    # IPAM\n    ('vrf', {\n        'queryset': VRF.objects.select_related('tenant'),\n        'filter': VRFFilter,\n        'table': VRFTable,\n        'url': 'ipam:vrf_list',\n    }),\n    ('aggregate', {\n        'queryset': Aggregate.objects.select_related('rir'),\n        'filter': AggregateFilter,\n        'table': AggregateTable,\n        'url': 'ipam:aggregate_list',\n    }),\n    ('prefix', {\n        'queryset': Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'),\n        'filter': PrefixFilter,\n        'table': PrefixTable,\n        'url': 'ipam:prefix_list',\n    }),\n    ('ipaddress', {\n        'queryset': IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device'),\n        'filter': IPAddressFilter,\n        'table': IPAddressTable,\n        'url': 'ipam:ipaddress_list',\n    }),\n    ('vlan', {\n        'queryset': VLAN.objects.select_related('site', 'group', 'tenant', 'role'),\n        'filter': VLANFilter,\n        'table': VLANTable,\n        'url': 'ipam:vlan_list',\n    }),\n    # Secrets\n    ('secret', {\n        'queryset': Secret.objects.select_related('role', 'device'),\n        'filter': SecretFilter,\n        'table': SecretTable,\n        'url': 'secrets:secret_list',\n    }),\n    # Tenancy\n    ('tenant', {\n        'queryset': Tenant.objects.select_related('group'),\n        'filter': TenantFilter,\n        'table': TenantTable,\n        'url': 'tenancy:tenant_list',\n    }),\n))\n\n\nclass HomeView(View):\n    template_name = 'home.html'\n\n    def get(self, request):\n\n        stats = {\n\n            # Organization\n            'site_count': Site.objects.count(),\n            'tenant_count': Tenant.objects.count(),\n\n            # DCIM\n            'rack_count': Rack.objects.count(),\n            'device_count': Device.objects.count(),\n            'interface_connections_count': InterfaceConnection.objects.count(),\n            'console_connections_count': ConsolePort.objects.filter(cs_port__isnull=False).count(),\n            'power_connections_count': PowerPort.objects.filter(power_outlet__isnull=False).count(),\n\n            # IPAM\n            'vrf_count': VRF.objects.count(),\n            'aggregate_count': Aggregate.objects.count(),\n            'prefix_count': Prefix.objects.count(),\n            'ipaddress_count': IPAddress.objects.count(),\n            'vlan_count': VLAN.objects.count(),\n\n            # Circuits\n            'provider_count': Provider.objects.count(),\n            'circuit_count': Circuit.objects.count(),\n\n            # Secrets\n            'secret_count': Secret.objects.count(),\n\n        }\n\n        return render(request, self.template_name, {\n            'search_form': SearchForm(),\n            'stats': stats,\n            'topology_maps': TopologyMap.objects.filter(site__isnull=True),\n            'recent_activity': UserAction.objects.select_related('user')[:50]\n        })\n\n\nclass SearchView(View):\n\n    def get(self, request):\n\n        # No query\n        if 'q' not in request.GET:\n            return render(request, 'search.html', {\n                'form': SearchForm(),\n            })\n\n        form = SearchForm(request.GET)\n        results = []\n\n        if form.is_valid():\n\n            # Searching for a single type of object\n            if form.cleaned_data['obj_type']:\n                obj_types = [form.cleaned_data['obj_type']]\n            # Searching all object types\n            else:\n                obj_types = SEARCH_TYPES.keys()\n\n            for obj_type in obj_types:\n\n                queryset = SEARCH_TYPES[obj_type]['queryset']\n                filter_cls = SEARCH_TYPES[obj_type]['filter']\n                table = SEARCH_TYPES[obj_type]['table']\n                url = SEARCH_TYPES[obj_type]['url']\n\n                # Construct the results table for this object type\n                filtered_queryset = filter_cls({'q': form.cleaned_data['q']}, queryset=queryset).qs\n                table = table(filtered_queryset, orderable=False)\n                table.paginate(per_page=SEARCH_MAX_RESULTS)\n\n                if table.page:\n                    results.append({\n                        'name': queryset.model._meta.verbose_name_plural,\n                        'table': table,\n                        'url': '{}?q={}'.format(reverse(url), form.cleaned_data['q'])\n                    })\n\n        return render(request, 'search.html', {\n            'form': form,\n            'results': results,\n        })\n\n\nclass APIRootView(APIView):\n    _ignore_model_permissions = True\n    exclude_from_schema = True\n\n    def get_view_name(self):\n        return \"API Root\"\n\n    def get(self, request, format=None):\n\n        return Response({\n            'circuits': reverse('circuits-api:api-root', request=request, format=format),\n            'dcim': reverse('dcim-api:api-root', request=request, format=format),\n            'extras': reverse('extras-api:api-root', request=request, format=format),\n            'ipam': reverse('ipam-api:api-root', request=request, format=format),\n            'secrets': reverse('secrets-api:api-root', request=request, format=format),\n            'tenancy': reverse('tenancy-api:api-root', request=request, format=format),\n        })\n\n\ndef handle_500(request):\n    \"\"\"\n    Custom server error handler\n    \"\"\"\n    type_, error, traceback = sys.exc_info()\n    return render(request, '500.html', {\n        'exception': str(type_),\n        'error': error,\n    }, status=500)\n\n\ndef trigger_500(request):\n    \"\"\"\n    Hot-wired method of triggering a server error to test reporting\n    \"\"\"\n    raise Exception(\n        \"Congratulations, you've triggered an exception! Go tell all your friends what an exceptional person you are.\"\n    )\n", "path": "netbox/netbox/views.py"}], "after_files": [{"content": "from __future__ import unicode_literals\nfrom collections import OrderedDict\nimport sys\n\nfrom rest_framework.views import APIView\nfrom rest_framework.response import Response\nfrom rest_framework.reverse import reverse\n\nfrom django.shortcuts import render\nfrom django.views.generic import View\n\nfrom circuits.filters import CircuitFilter, ProviderFilter\nfrom circuits.models import Circuit, Provider\nfrom circuits.tables import CircuitTable, ProviderTable\nfrom dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter\nfrom dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site\nfrom dcim.tables import DeviceDetailTable, DeviceTypeTable, RackTable, SiteTable\nfrom extras.models import TopologyMap, UserAction\nfrom ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter\nfrom ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF\nfrom ipam.tables import AggregateTable, IPAddressTable, PrefixTable, VLANTable, VRFTable\nfrom secrets.filters import SecretFilter\nfrom secrets.models import Secret\nfrom secrets.tables import SecretTable\nfrom tenancy.filters import TenantFilter\nfrom tenancy.models import Tenant\nfrom tenancy.tables import TenantTable\nfrom .forms import SearchForm\n\n\nSEARCH_MAX_RESULTS = 15\nSEARCH_TYPES = OrderedDict((\n    # Circuits\n    ('provider', {\n        'queryset': Provider.objects.all(),\n        'filter': ProviderFilter,\n        'table': ProviderTable,\n        'url': 'circuits:provider_list',\n    }),\n    ('circuit', {\n        'queryset': Circuit.objects.select_related('type', 'provider', 'tenant').prefetch_related('terminations__site'),\n        'filter': CircuitFilter,\n        'table': CircuitTable,\n        'url': 'circuits:circuit_list',\n    }),\n    # DCIM\n    ('site', {\n        'queryset': Site.objects.select_related('region', 'tenant'),\n        'filter': SiteFilter,\n        'table': SiteTable,\n        'url': 'dcim:site_list',\n    }),\n    ('rack', {\n        'queryset': Rack.objects.select_related('site', 'group', 'tenant', 'role'),\n        'filter': RackFilter,\n        'table': RackTable,\n        'url': 'dcim:rack_list',\n    }),\n    ('devicetype', {\n        'queryset': DeviceType.objects.select_related('manufacturer'),\n        'filter': DeviceTypeFilter,\n        'table': DeviceTypeTable,\n        'url': 'dcim:devicetype_list',\n    }),\n    ('device', {\n        'queryset': Device.objects.select_related(\n            'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack'\n        ),\n        'filter': DeviceFilter,\n        'table': DeviceDetailTable,\n        'url': 'dcim:device_list',\n    }),\n    # IPAM\n    ('vrf', {\n        'queryset': VRF.objects.select_related('tenant'),\n        'filter': VRFFilter,\n        'table': VRFTable,\n        'url': 'ipam:vrf_list',\n    }),\n    ('aggregate', {\n        'queryset': Aggregate.objects.select_related('rir'),\n        'filter': AggregateFilter,\n        'table': AggregateTable,\n        'url': 'ipam:aggregate_list',\n    }),\n    ('prefix', {\n        'queryset': Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'),\n        'filter': PrefixFilter,\n        'table': PrefixTable,\n        'url': 'ipam:prefix_list',\n    }),\n    ('ipaddress', {\n        'queryset': IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device'),\n        'filter': IPAddressFilter,\n        'table': IPAddressTable,\n        'url': 'ipam:ipaddress_list',\n    }),\n    ('vlan', {\n        'queryset': VLAN.objects.select_related('site', 'group', 'tenant', 'role'),\n        'filter': VLANFilter,\n        'table': VLANTable,\n        'url': 'ipam:vlan_list',\n    }),\n    # Secrets\n    ('secret', {\n        'queryset': Secret.objects.select_related('role', 'device'),\n        'filter': SecretFilter,\n        'table': SecretTable,\n        'url': 'secrets:secret_list',\n    }),\n    # Tenancy\n    ('tenant', {\n        'queryset': Tenant.objects.select_related('group'),\n        'filter': TenantFilter,\n        'table': TenantTable,\n        'url': 'tenancy:tenant_list',\n    }),\n))\n\n\nclass HomeView(View):\n    template_name = 'home.html'\n\n    def get(self, request):\n\n        stats = {\n\n            # Organization\n            'site_count': Site.objects.count(),\n            'tenant_count': Tenant.objects.count(),\n\n            # DCIM\n            'rack_count': Rack.objects.count(),\n            'device_count': Device.objects.count(),\n            'interface_connections_count': InterfaceConnection.objects.count(),\n            'console_connections_count': ConsolePort.objects.filter(cs_port__isnull=False).count(),\n            'power_connections_count': PowerPort.objects.filter(power_outlet__isnull=False).count(),\n\n            # IPAM\n            'vrf_count': VRF.objects.count(),\n            'aggregate_count': Aggregate.objects.count(),\n            'prefix_count': Prefix.objects.count(),\n            'ipaddress_count': IPAddress.objects.count(),\n            'vlan_count': VLAN.objects.count(),\n\n            # Circuits\n            'provider_count': Provider.objects.count(),\n            'circuit_count': Circuit.objects.count(),\n\n            # Secrets\n            'secret_count': Secret.objects.count(),\n\n        }\n\n        return render(request, self.template_name, {\n            'search_form': SearchForm(),\n            'stats': stats,\n            'topology_maps': TopologyMap.objects.filter(site__isnull=True),\n            'recent_activity': UserAction.objects.select_related('user')[:50]\n        })\n\n\nclass SearchView(View):\n\n    def get(self, request):\n\n        # No query\n        if 'q' not in request.GET:\n            return render(request, 'search.html', {\n                'form': SearchForm(),\n            })\n\n        form = SearchForm(request.GET)\n        results = []\n\n        if form.is_valid():\n\n            # Searching for a single type of object\n            if form.cleaned_data['obj_type']:\n                obj_types = [form.cleaned_data['obj_type']]\n            # Searching all object types\n            else:\n                obj_types = SEARCH_TYPES.keys()\n\n            for obj_type in obj_types:\n\n                queryset = SEARCH_TYPES[obj_type]['queryset']\n                filter_cls = SEARCH_TYPES[obj_type]['filter']\n                table = SEARCH_TYPES[obj_type]['table']\n                url = SEARCH_TYPES[obj_type]['url']\n\n                # Construct the results table for this object type\n                filtered_queryset = filter_cls({'q': form.cleaned_data['q']}, queryset=queryset).qs\n                table = table(filtered_queryset, orderable=False)\n                table.paginate(per_page=SEARCH_MAX_RESULTS)\n\n                if table.page:\n                    results.append({\n                        'name': queryset.model._meta.verbose_name_plural,\n                        'table': table,\n                        'url': '{}?q={}'.format(reverse(url), form.cleaned_data['q'])\n                    })\n\n        return render(request, 'search.html', {\n            'form': form,\n            'results': results,\n        })\n\n\nclass APIRootView(APIView):\n    _ignore_model_permissions = True\n    exclude_from_schema = True\n\n    def get_view_name(self):\n        return \"API Root\"\n\n    def get(self, request, format=None):\n\n        return Response({\n            'circuits': reverse('circuits-api:api-root', request=request, format=format),\n            'dcim': reverse('dcim-api:api-root', request=request, format=format),\n            'extras': reverse('extras-api:api-root', request=request, format=format),\n            'ipam': reverse('ipam-api:api-root', request=request, format=format),\n            'secrets': reverse('secrets-api:api-root', request=request, format=format),\n            'tenancy': reverse('tenancy-api:api-root', request=request, format=format),\n        })\n\n\ndef handle_500(request):\n    \"\"\"\n    Custom server error handler\n    \"\"\"\n    type_, error, traceback = sys.exc_info()\n    return render(request, '500.html', {\n        'exception': str(type_),\n        'error': error,\n    }, status=500)\n\n\ndef trigger_500(request):\n    \"\"\"\n    Hot-wired method of triggering a server error to test reporting\n    \"\"\"\n    raise Exception(\n        \"Congratulations, you've triggered an exception! Go tell all your friends what an exceptional person you are.\"\n    )\n", "path": "netbox/netbox/views.py"}]}