We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add Pagination to Provider Detail View
<!--
    NOTE: This form is only for proposing specific new features or enhancements.
    If you have a general idea or question, please post to our mailing list
    instead of opening an issue:

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

    NOTE: Due to an excessive backlog of feature requests, we are not currently
    accepting any proposals which significantly extend NetBox's feature scope.

    Please describe the environment in which you are running NetBox. Be sure
    that you are running an unmodified instance of the latest stable release
    before submitting a bug report.
-->
### Environment
* Python version:  3.6.8 <!-- Example: 3.5.4 -->
* NetBox version:  2.5.13 <!-- Example: 2.3.6 -->

<!--
    Describe in detail the new functionality you are proposing. Include any
    specific changes to work flows, data models, or the user interface.
-->
### Proposed Functionality

Similar to https://github.com/netbox-community/netbox/issues/3314, the provider detail circuit listing would benefit from pagination when the object count is higher than a few hundred entries.

Edit: Same goes for IP Address detail page (Related and Duplicate IPs) (`/ipam/ip-addresses/<id>/`)

<!--
    Convey an example use case for your proposed feature. Write from the
    perspective of a NetBox user who would benefit from the proposed
    functionality and describe how.
--->
### Use Case

When viewing Providers (e.g., `/circuits/providers/att/`) with a high number of circuits, the page loads very slow (and performs a larger DB query). Adding pagination will reduce the load on the webserver and the DB.

Edit: Same goes for IP Address detail page (Related and Duplicate IPs) (`/ipam/ip-addresses/<id>/`)

<!--
    Note any changes to the database schema necessary to support the new
    feature. For example, does the proposal require adding a new model or
    field? (Not all new features require database changes.)
--->
### Database Changes
 NA

<!--
    List any new dependencies on external libraries or services that this new
    feature would introduce. For example, does the proposal require the
    installation of a new Python package? (Not all new features introduce new
    dependencies.)
-->
### External Dependencies
NA

--- 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/circuits/views.py`
Content:
```
1 from django.contrib import messages
2 from django.contrib.auth.decorators import permission_required
3 from django.contrib.auth.mixins import PermissionRequiredMixin
4 from django.db import transaction
5 from django.db.models import Count, OuterRef, Subquery
6 from django.shortcuts import get_object_or_404, redirect, render
7 from django.views.generic import View
8 
9 from extras.models import Graph, GRAPH_TYPE_PROVIDER
10 from utilities.forms import ConfirmationForm
11 from utilities.views import (
12     BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
13 )
14 from . import filters, forms, tables
15 from .constants import TERM_SIDE_A, TERM_SIDE_Z
16 from .models import Circuit, CircuitTermination, CircuitType, Provider
17 
18 
19 #
20 # Providers
21 #
22 
23 class ProviderListView(PermissionRequiredMixin, ObjectListView):
24     permission_required = 'circuits.view_provider'
25     queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
26     filter = filters.ProviderFilter
27     filter_form = forms.ProviderFilterForm
28     table = tables.ProviderDetailTable
29     template_name = 'circuits/provider_list.html'
30 
31 
32 class ProviderView(PermissionRequiredMixin, View):
33     permission_required = 'circuits.view_provider'
34 
35     def get(self, request, slug):
36 
37         provider = get_object_or_404(Provider, slug=slug)
38         circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site')
39         show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()
40 
41         return render(request, 'circuits/provider.html', {
42             'provider': provider,
43             'circuits': circuits,
44             'show_graphs': show_graphs,
45         })
46 
47 
48 class ProviderCreateView(PermissionRequiredMixin, ObjectEditView):
49     permission_required = 'circuits.add_provider'
50     model = Provider
51     model_form = forms.ProviderForm
52     template_name = 'circuits/provider_edit.html'
53     default_return_url = 'circuits:provider_list'
54 
55 
56 class ProviderEditView(ProviderCreateView):
57     permission_required = 'circuits.change_provider'
58 
59 
60 class ProviderDeleteView(PermissionRequiredMixin, ObjectDeleteView):
61     permission_required = 'circuits.delete_provider'
62     model = Provider
63     default_return_url = 'circuits:provider_list'
64 
65 
66 class ProviderBulkImportView(PermissionRequiredMixin, BulkImportView):
67     permission_required = 'circuits.add_provider'
68     model_form = forms.ProviderCSVForm
69     table = tables.ProviderTable
70     default_return_url = 'circuits:provider_list'
71 
72 
73 class ProviderBulkEditView(PermissionRequiredMixin, BulkEditView):
74     permission_required = 'circuits.change_provider'
75     queryset = Provider.objects.all()
76     filter = filters.ProviderFilter
77     table = tables.ProviderTable
78     form = forms.ProviderBulkEditForm
79     default_return_url = 'circuits:provider_list'
80 
81 
82 class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
83     permission_required = 'circuits.delete_provider'
84     queryset = Provider.objects.all()
85     filter = filters.ProviderFilter
86     table = tables.ProviderTable
87     default_return_url = 'circuits:provider_list'
88 
89 
90 #
91 # Circuit Types
92 #
93 
94 class CircuitTypeListView(PermissionRequiredMixin, ObjectListView):
95     permission_required = 'circuits.view_circuittype'
96     queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
97     table = tables.CircuitTypeTable
98     template_name = 'circuits/circuittype_list.html'
99 
100 
101 class CircuitTypeCreateView(PermissionRequiredMixin, ObjectEditView):
102     permission_required = 'circuits.add_circuittype'
103     model = CircuitType
104     model_form = forms.CircuitTypeForm
105     default_return_url = 'circuits:circuittype_list'
106 
107 
108 class CircuitTypeEditView(CircuitTypeCreateView):
109     permission_required = 'circuits.change_circuittype'
110 
111 
112 class CircuitTypeBulkImportView(PermissionRequiredMixin, BulkImportView):
113     permission_required = 'circuits.add_circuittype'
114     model_form = forms.CircuitTypeCSVForm
115     table = tables.CircuitTypeTable
116     default_return_url = 'circuits:circuittype_list'
117 
118 
119 class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
120     permission_required = 'circuits.delete_circuittype'
121     queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
122     table = tables.CircuitTypeTable
123     default_return_url = 'circuits:circuittype_list'
124 
125 
126 #
127 # Circuits
128 #
129 
130 class CircuitListView(PermissionRequiredMixin, ObjectListView):
131     permission_required = 'circuits.view_circuit'
132     _terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk'))
133     queryset = Circuit.objects.prefetch_related(
134         'provider', 'type', 'tenant', 'terminations__site'
135     ).annotate(
136         a_side=Subquery(_terminations.filter(term_side='A').values('site__name')[:1]),
137         z_side=Subquery(_terminations.filter(term_side='Z').values('site__name')[:1]),
138     )
139     filter = filters.CircuitFilter
140     filter_form = forms.CircuitFilterForm
141     table = tables.CircuitTable
142     template_name = 'circuits/circuit_list.html'
143 
144 
145 class CircuitView(PermissionRequiredMixin, View):
146     permission_required = 'circuits.view_circuit'
147 
148     def get(self, request, pk):
149 
150         circuit = get_object_or_404(Circuit.objects.prefetch_related('provider', 'type', 'tenant__group'), pk=pk)
151         termination_a = CircuitTermination.objects.prefetch_related(
152             'site__region', 'connected_endpoint__device'
153         ).filter(
154             circuit=circuit, term_side=TERM_SIDE_A
155         ).first()
156         termination_z = CircuitTermination.objects.prefetch_related(
157             'site__region', 'connected_endpoint__device'
158         ).filter(
159             circuit=circuit, term_side=TERM_SIDE_Z
160         ).first()
161 
162         return render(request, 'circuits/circuit.html', {
163             'circuit': circuit,
164             'termination_a': termination_a,
165             'termination_z': termination_z,
166         })
167 
168 
169 class CircuitCreateView(PermissionRequiredMixin, ObjectEditView):
170     permission_required = 'circuits.add_circuit'
171     model = Circuit
172     model_form = forms.CircuitForm
173     template_name = 'circuits/circuit_edit.html'
174     default_return_url = 'circuits:circuit_list'
175 
176 
177 class CircuitEditView(CircuitCreateView):
178     permission_required = 'circuits.change_circuit'
179 
180 
181 class CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):
182     permission_required = 'circuits.delete_circuit'
183     model = Circuit
184     default_return_url = 'circuits:circuit_list'
185 
186 
187 class CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):
188     permission_required = 'circuits.add_circuit'
189     model_form = forms.CircuitCSVForm
190     table = tables.CircuitTable
191     default_return_url = 'circuits:circuit_list'
192 
193 
194 class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
195     permission_required = 'circuits.change_circuit'
196     queryset = Circuit.objects.prefetch_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
197     filter = filters.CircuitFilter
198     table = tables.CircuitTable
199     form = forms.CircuitBulkEditForm
200     default_return_url = 'circuits:circuit_list'
201 
202 
203 class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
204     permission_required = 'circuits.delete_circuit'
205     queryset = Circuit.objects.prefetch_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
206     filter = filters.CircuitFilter
207     table = tables.CircuitTable
208     default_return_url = 'circuits:circuit_list'
209 
210 
211 @permission_required('circuits.change_circuittermination')
212 def circuit_terminations_swap(request, pk):
213 
214     circuit = get_object_or_404(Circuit, pk=pk)
215     termination_a = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_A).first()
216     termination_z = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_Z).first()
217     if not termination_a and not termination_z:
218         messages.error(request, "No terminations have been defined for circuit {}.".format(circuit))
219         return redirect('circuits:circuit', pk=circuit.pk)
220 
221     if request.method == 'POST':
222         form = ConfirmationForm(request.POST)
223         if form.is_valid():
224             if termination_a and termination_z:
225                 # Use a placeholder to avoid an IntegrityError on the (circuit, term_side) unique constraint
226                 with transaction.atomic():
227                     termination_a.term_side = '_'
228                     termination_a.save()
229                     termination_z.term_side = 'A'
230                     termination_z.save()
231                     termination_a.term_side = 'Z'
232                     termination_a.save()
233             elif termination_a:
234                 termination_a.term_side = 'Z'
235                 termination_a.save()
236             else:
237                 termination_z.term_side = 'A'
238                 termination_z.save()
239             messages.success(request, "Swapped terminations for circuit {}.".format(circuit))
240             return redirect('circuits:circuit', pk=circuit.pk)
241 
242     else:
243         form = ConfirmationForm()
244 
245     return render(request, 'circuits/circuit_terminations_swap.html', {
246         'circuit': circuit,
247         'termination_a': termination_a,
248         'termination_z': termination_z,
249         'form': form,
250         'panel_class': 'default',
251         'button_class': 'primary',
252         'return_url': circuit.get_absolute_url(),
253     })
254 
255 
256 #
257 # Circuit terminations
258 #
259 
260 class CircuitTerminationCreateView(PermissionRequiredMixin, ObjectEditView):
261     permission_required = 'circuits.add_circuittermination'
262     model = CircuitTermination
263     model_form = forms.CircuitTerminationForm
264     template_name = 'circuits/circuittermination_edit.html'
265 
266     def alter_obj(self, obj, request, url_args, url_kwargs):
267         if 'circuit' in url_kwargs:
268             obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit'])
269         return obj
270 
271     def get_return_url(self, request, obj):
272         return obj.circuit.get_absolute_url()
273 
274 
275 class CircuitTerminationEditView(CircuitTerminationCreateView):
276     permission_required = 'circuits.change_circuittermination'
277 
278 
279 class CircuitTerminationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
280     permission_required = 'circuits.delete_circuittermination'
281     model = CircuitTermination
282
```
--- 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/circuits/views.py b/netbox/circuits/views.py
--- a/netbox/circuits/views.py
+++ b/netbox/circuits/views.py
@@ -1,3 +1,4 @@
+from django.conf import settings
 from django.contrib import messages
 from django.contrib.auth.decorators import permission_required
 from django.contrib.auth.mixins import PermissionRequiredMixin
@@ -5,9 +6,11 @@
 from django.db.models import Count, OuterRef, Subquery
 from django.shortcuts import get_object_or_404, redirect, render
 from django.views.generic import View
+from django_tables2 import RequestConfig
 
 from extras.models import Graph, GRAPH_TYPE_PROVIDER
 from utilities.forms import ConfirmationForm
+from utilities.paginator import EnhancedPaginator
 from utilities.views import (
     BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
 )
@@ -38,9 +41,18 @@
         circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site')
         show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()
 
+        circuits_table = tables.CircuitTable(circuits, orderable=False)
+        circuits_table.columns.hide('provider')
+
+        paginate = {
+            'paginator_class': EnhancedPaginator,
+            'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
+        }
+        RequestConfig(request, paginate).configure(circuits_table)
+
         return render(request, 'circuits/provider.html', {
             'provider': provider,
-            'circuits': circuits,
+            'circuits_table': circuits_table,
             'show_graphs': show_graphs,
         })

{"golden_diff": "diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py\n--- a/netbox/circuits/views.py\n+++ b/netbox/circuits/views.py\n@@ -1,3 +1,4 @@\n+from django.conf import settings\n from django.contrib import messages\n from django.contrib.auth.decorators import permission_required\n from django.contrib.auth.mixins import PermissionRequiredMixin\n@@ -5,9 +6,11 @@\n from django.db.models import Count, OuterRef, Subquery\n from django.shortcuts import get_object_or_404, redirect, render\n from django.views.generic import View\n+from django_tables2 import RequestConfig\n \n from extras.models import Graph, GRAPH_TYPE_PROVIDER\n from utilities.forms import ConfirmationForm\n+from utilities.paginator import EnhancedPaginator\n from utilities.views import (\n     BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,\n )\n@@ -38,9 +41,18 @@\n         circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site')\n         show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()\n \n+        circuits_table = tables.CircuitTable(circuits, orderable=False)\n+        circuits_table.columns.hide('provider')\n+\n+        paginate = {\n+            'paginator_class': EnhancedPaginator,\n+            'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)\n+        }\n+        RequestConfig(request, paginate).configure(circuits_table)\n+\n         return render(request, 'circuits/provider.html', {\n             'provider': provider,\n-            'circuits': circuits,\n+            'circuits_table': circuits_table,\n             'show_graphs': show_graphs,\n         })\n", "issue": "Add Pagination to Provider Detail View\n<!--\r\n    NOTE: This form is only for proposing specific new features or enhancements.\r\n    If you have a general idea or question, please post to our mailing list\r\n    instead of opening an issue:\r\n\r\n        https://groups.google.com/forum/#!forum/netbox-discuss\r\n\r\n    NOTE: Due to an excessive backlog of feature requests, we are not currently\r\n    accepting any proposals which significantly extend NetBox's feature scope.\r\n\r\n    Please describe the environment in which you are running NetBox. Be sure\r\n    that you are running an unmodified instance of the latest stable release\r\n    before submitting a bug report.\r\n-->\r\n### Environment\r\n* Python version:  3.6.8 <!-- Example: 3.5.4 -->\r\n* NetBox version:  2.5.13 <!-- Example: 2.3.6 -->\r\n\r\n<!--\r\n    Describe in detail the new functionality you are proposing. Include any\r\n    specific changes to work flows, data models, or the user interface.\r\n-->\r\n### Proposed Functionality\r\n\r\nSimilar to https://github.com/netbox-community/netbox/issues/3314, the provider detail circuit listing would benefit from pagination when the object count is higher than a few hundred entries.\r\n\r\nEdit: Same goes for IP Address detail page (Related and Duplicate IPs) (`/ipam/ip-addresses/<id>/`)\r\n\r\n<!--\r\n    Convey an example use case for your proposed feature. Write from the\r\n    perspective of a NetBox user who would benefit from the proposed\r\n    functionality and describe how.\r\n--->\r\n### Use Case\r\n\r\nWhen viewing Providers (e.g., `/circuits/providers/att/`) with a high number of circuits, the page loads very slow (and performs a larger DB query). Adding pagination will reduce the load on the webserver and the DB.\r\n\r\nEdit: Same goes for IP Address detail page (Related and Duplicate IPs) (`/ipam/ip-addresses/<id>/`)\r\n\r\n<!--\r\n    Note any changes to the database schema necessary to support the new\r\n    feature. For example, does the proposal require adding a new model or\r\n    field? (Not all new features require database changes.)\r\n--->\r\n### Database Changes\r\n NA\r\n\r\n<!--\r\n    List any new dependencies on external libraries or services that this new\r\n    feature would introduce. For example, does the proposal require the\r\n    installation of a new Python package? (Not all new features introduce new\r\n    dependencies.)\r\n-->\r\n### External Dependencies\r\nNA\n", "before_files": [{"content": "from django.contrib import messages\nfrom django.contrib.auth.decorators import permission_required\nfrom django.contrib.auth.mixins import PermissionRequiredMixin\nfrom django.db import transaction\nfrom django.db.models import Count, OuterRef, Subquery\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.views.generic import View\n\nfrom extras.models import Graph, GRAPH_TYPE_PROVIDER\nfrom utilities.forms import ConfirmationForm\nfrom utilities.views import (\n    BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,\n)\nfrom . import filters, forms, tables\nfrom .constants import TERM_SIDE_A, TERM_SIDE_Z\nfrom .models import Circuit, CircuitTermination, CircuitType, Provider\n\n\n#\n# Providers\n#\n\nclass ProviderListView(PermissionRequiredMixin, ObjectListView):\n    permission_required = 'circuits.view_provider'\n    queryset = Provider.objects.annotate(count_circuits=Count('circuits'))\n    filter = filters.ProviderFilter\n    filter_form = forms.ProviderFilterForm\n    table = tables.ProviderDetailTable\n    template_name = 'circuits/provider_list.html'\n\n\nclass ProviderView(PermissionRequiredMixin, View):\n    permission_required = 'circuits.view_provider'\n\n    def get(self, request, slug):\n\n        provider = get_object_or_404(Provider, slug=slug)\n        circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site')\n        show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()\n\n        return render(request, 'circuits/provider.html', {\n            'provider': provider,\n            'circuits': circuits,\n            'show_graphs': show_graphs,\n        })\n\n\nclass ProviderCreateView(PermissionRequiredMixin, ObjectEditView):\n    permission_required = 'circuits.add_provider'\n    model = Provider\n    model_form = forms.ProviderForm\n    template_name = 'circuits/provider_edit.html'\n    default_return_url = 'circuits:provider_list'\n\n\nclass ProviderEditView(ProviderCreateView):\n    permission_required = 'circuits.change_provider'\n\n\nclass ProviderDeleteView(PermissionRequiredMixin, ObjectDeleteView):\n    permission_required = 'circuits.delete_provider'\n    model = Provider\n    default_return_url = 'circuits:provider_list'\n\n\nclass ProviderBulkImportView(PermissionRequiredMixin, BulkImportView):\n    permission_required = 'circuits.add_provider'\n    model_form = forms.ProviderCSVForm\n    table = tables.ProviderTable\n    default_return_url = 'circuits:provider_list'\n\n\nclass ProviderBulkEditView(PermissionRequiredMixin, BulkEditView):\n    permission_required = 'circuits.change_provider'\n    queryset = Provider.objects.all()\n    filter = filters.ProviderFilter\n    table = tables.ProviderTable\n    form = forms.ProviderBulkEditForm\n    default_return_url = 'circuits:provider_list'\n\n\nclass ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):\n    permission_required = 'circuits.delete_provider'\n    queryset = Provider.objects.all()\n    filter = filters.ProviderFilter\n    table = tables.ProviderTable\n    default_return_url = 'circuits:provider_list'\n\n\n#\n# Circuit Types\n#\n\nclass CircuitTypeListView(PermissionRequiredMixin, ObjectListView):\n    permission_required = 'circuits.view_circuittype'\n    queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))\n    table = tables.CircuitTypeTable\n    template_name = 'circuits/circuittype_list.html'\n\n\nclass CircuitTypeCreateView(PermissionRequiredMixin, ObjectEditView):\n    permission_required = 'circuits.add_circuittype'\n    model = CircuitType\n    model_form = forms.CircuitTypeForm\n    default_return_url = 'circuits:circuittype_list'\n\n\nclass CircuitTypeEditView(CircuitTypeCreateView):\n    permission_required = 'circuits.change_circuittype'\n\n\nclass CircuitTypeBulkImportView(PermissionRequiredMixin, BulkImportView):\n    permission_required = 'circuits.add_circuittype'\n    model_form = forms.CircuitTypeCSVForm\n    table = tables.CircuitTypeTable\n    default_return_url = 'circuits:circuittype_list'\n\n\nclass CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):\n    permission_required = 'circuits.delete_circuittype'\n    queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))\n    table = tables.CircuitTypeTable\n    default_return_url = 'circuits:circuittype_list'\n\n\n#\n# Circuits\n#\n\nclass CircuitListView(PermissionRequiredMixin, ObjectListView):\n    permission_required = 'circuits.view_circuit'\n    _terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk'))\n    queryset = Circuit.objects.prefetch_related(\n        'provider', 'type', 'tenant', 'terminations__site'\n    ).annotate(\n        a_side=Subquery(_terminations.filter(term_side='A').values('site__name')[:1]),\n        z_side=Subquery(_terminations.filter(term_side='Z').values('site__name')[:1]),\n    )\n    filter = filters.CircuitFilter\n    filter_form = forms.CircuitFilterForm\n    table = tables.CircuitTable\n    template_name = 'circuits/circuit_list.html'\n\n\nclass CircuitView(PermissionRequiredMixin, View):\n    permission_required = 'circuits.view_circuit'\n\n    def get(self, request, pk):\n\n        circuit = get_object_or_404(Circuit.objects.prefetch_related('provider', 'type', 'tenant__group'), pk=pk)\n        termination_a = CircuitTermination.objects.prefetch_related(\n            'site__region', 'connected_endpoint__device'\n        ).filter(\n            circuit=circuit, term_side=TERM_SIDE_A\n        ).first()\n        termination_z = CircuitTermination.objects.prefetch_related(\n            'site__region', 'connected_endpoint__device'\n        ).filter(\n            circuit=circuit, term_side=TERM_SIDE_Z\n        ).first()\n\n        return render(request, 'circuits/circuit.html', {\n            'circuit': circuit,\n            'termination_a': termination_a,\n            'termination_z': termination_z,\n        })\n\n\nclass CircuitCreateView(PermissionRequiredMixin, ObjectEditView):\n    permission_required = 'circuits.add_circuit'\n    model = Circuit\n    model_form = forms.CircuitForm\n    template_name = 'circuits/circuit_edit.html'\n    default_return_url = 'circuits:circuit_list'\n\n\nclass CircuitEditView(CircuitCreateView):\n    permission_required = 'circuits.change_circuit'\n\n\nclass CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):\n    permission_required = 'circuits.delete_circuit'\n    model = Circuit\n    default_return_url = 'circuits:circuit_list'\n\n\nclass CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):\n    permission_required = 'circuits.add_circuit'\n    model_form = forms.CircuitCSVForm\n    table = tables.CircuitTable\n    default_return_url = 'circuits:circuit_list'\n\n\nclass CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):\n    permission_required = 'circuits.change_circuit'\n    queryset = Circuit.objects.prefetch_related('provider', 'type', 'tenant').prefetch_related('terminations__site')\n    filter = filters.CircuitFilter\n    table = tables.CircuitTable\n    form = forms.CircuitBulkEditForm\n    default_return_url = 'circuits:circuit_list'\n\n\nclass CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):\n    permission_required = 'circuits.delete_circuit'\n    queryset = Circuit.objects.prefetch_related('provider', 'type', 'tenant').prefetch_related('terminations__site')\n    filter = filters.CircuitFilter\n    table = tables.CircuitTable\n    default_return_url = 'circuits:circuit_list'\n\n\n@permission_required('circuits.change_circuittermination')\ndef circuit_terminations_swap(request, pk):\n\n    circuit = get_object_or_404(Circuit, pk=pk)\n    termination_a = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_A).first()\n    termination_z = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_Z).first()\n    if not termination_a and not termination_z:\n        messages.error(request, \"No terminations have been defined for circuit {}.\".format(circuit))\n        return redirect('circuits:circuit', pk=circuit.pk)\n\n    if request.method == 'POST':\n        form = ConfirmationForm(request.POST)\n        if form.is_valid():\n            if termination_a and termination_z:\n                # Use a placeholder to avoid an IntegrityError on the (circuit, term_side) unique constraint\n                with transaction.atomic():\n                    termination_a.term_side = '_'\n                    termination_a.save()\n                    termination_z.term_side = 'A'\n                    termination_z.save()\n                    termination_a.term_side = 'Z'\n                    termination_a.save()\n            elif termination_a:\n                termination_a.term_side = 'Z'\n                termination_a.save()\n            else:\n                termination_z.term_side = 'A'\n                termination_z.save()\n            messages.success(request, \"Swapped terminations for circuit {}.\".format(circuit))\n            return redirect('circuits:circuit', pk=circuit.pk)\n\n    else:\n        form = ConfirmationForm()\n\n    return render(request, 'circuits/circuit_terminations_swap.html', {\n        'circuit': circuit,\n        'termination_a': termination_a,\n        'termination_z': termination_z,\n        'form': form,\n        'panel_class': 'default',\n        'button_class': 'primary',\n        'return_url': circuit.get_absolute_url(),\n    })\n\n\n#\n# Circuit terminations\n#\n\nclass CircuitTerminationCreateView(PermissionRequiredMixin, ObjectEditView):\n    permission_required = 'circuits.add_circuittermination'\n    model = CircuitTermination\n    model_form = forms.CircuitTerminationForm\n    template_name = 'circuits/circuittermination_edit.html'\n\n    def alter_obj(self, obj, request, url_args, url_kwargs):\n        if 'circuit' in url_kwargs:\n            obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit'])\n        return obj\n\n    def get_return_url(self, request, obj):\n        return obj.circuit.get_absolute_url()\n\n\nclass CircuitTerminationEditView(CircuitTerminationCreateView):\n    permission_required = 'circuits.change_circuittermination'\n\n\nclass CircuitTerminationDeleteView(PermissionRequiredMixin, ObjectDeleteView):\n    permission_required = 'circuits.delete_circuittermination'\n    model = CircuitTermination\n", "path": "netbox/circuits/views.py"}], "after_files": [{"content": "from django.conf import settings\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import permission_required\nfrom django.contrib.auth.mixins import PermissionRequiredMixin\nfrom django.db import transaction\nfrom django.db.models import Count, OuterRef, Subquery\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.views.generic import View\nfrom django_tables2 import RequestConfig\n\nfrom extras.models import Graph, GRAPH_TYPE_PROVIDER\nfrom utilities.forms import ConfirmationForm\nfrom utilities.paginator import EnhancedPaginator\nfrom utilities.views import (\n    BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,\n)\nfrom . import filters, forms, tables\nfrom .constants import TERM_SIDE_A, TERM_SIDE_Z\nfrom .models import Circuit, CircuitTermination, CircuitType, Provider\n\n\n#\n# Providers\n#\n\nclass ProviderListView(PermissionRequiredMixin, ObjectListView):\n    permission_required = 'circuits.view_provider'\n    queryset = Provider.objects.annotate(count_circuits=Count('circuits'))\n    filter = filters.ProviderFilter\n    filter_form = forms.ProviderFilterForm\n    table = tables.ProviderDetailTable\n    template_name = 'circuits/provider_list.html'\n\n\nclass ProviderView(PermissionRequiredMixin, View):\n    permission_required = 'circuits.view_provider'\n\n    def get(self, request, slug):\n\n        provider = get_object_or_404(Provider, slug=slug)\n        circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site')\n        show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()\n\n        circuits_table = tables.CircuitTable(circuits, orderable=False)\n        circuits_table.columns.hide('provider')\n\n        paginate = {\n            'paginator_class': EnhancedPaginator,\n            'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)\n        }\n        RequestConfig(request, paginate).configure(circuits_table)\n\n        return render(request, 'circuits/provider.html', {\n            'provider': provider,\n            'circuits_table': circuits_table,\n            'show_graphs': show_graphs,\n        })\n\n\nclass ProviderCreateView(PermissionRequiredMixin, ObjectEditView):\n    permission_required = 'circuits.add_provider'\n    model = Provider\n    model_form = forms.ProviderForm\n    template_name = 'circuits/provider_edit.html'\n    default_return_url = 'circuits:provider_list'\n\n\nclass ProviderEditView(ProviderCreateView):\n    permission_required = 'circuits.change_provider'\n\n\nclass ProviderDeleteView(PermissionRequiredMixin, ObjectDeleteView):\n    permission_required = 'circuits.delete_provider'\n    model = Provider\n    default_return_url = 'circuits:provider_list'\n\n\nclass ProviderBulkImportView(PermissionRequiredMixin, BulkImportView):\n    permission_required = 'circuits.add_provider'\n    model_form = forms.ProviderCSVForm\n    table = tables.ProviderTable\n    default_return_url = 'circuits:provider_list'\n\n\nclass ProviderBulkEditView(PermissionRequiredMixin, BulkEditView):\n    permission_required = 'circuits.change_provider'\n    queryset = Provider.objects.all()\n    filter = filters.ProviderFilter\n    table = tables.ProviderTable\n    form = forms.ProviderBulkEditForm\n    default_return_url = 'circuits:provider_list'\n\n\nclass ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):\n    permission_required = 'circuits.delete_provider'\n    queryset = Provider.objects.all()\n    filter = filters.ProviderFilter\n    table = tables.ProviderTable\n    default_return_url = 'circuits:provider_list'\n\n\n#\n# Circuit Types\n#\n\nclass CircuitTypeListView(PermissionRequiredMixin, ObjectListView):\n    permission_required = 'circuits.view_circuittype'\n    queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))\n    table = tables.CircuitTypeTable\n    template_name = 'circuits/circuittype_list.html'\n\n\nclass CircuitTypeCreateView(PermissionRequiredMixin, ObjectEditView):\n    permission_required = 'circuits.add_circuittype'\n    model = CircuitType\n    model_form = forms.CircuitTypeForm\n    default_return_url = 'circuits:circuittype_list'\n\n\nclass CircuitTypeEditView(CircuitTypeCreateView):\n    permission_required = 'circuits.change_circuittype'\n\n\nclass CircuitTypeBulkImportView(PermissionRequiredMixin, BulkImportView):\n    permission_required = 'circuits.add_circuittype'\n    model_form = forms.CircuitTypeCSVForm\n    table = tables.CircuitTypeTable\n    default_return_url = 'circuits:circuittype_list'\n\n\nclass CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):\n    permission_required = 'circuits.delete_circuittype'\n    queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))\n    table = tables.CircuitTypeTable\n    default_return_url = 'circuits:circuittype_list'\n\n\n#\n# Circuits\n#\n\nclass CircuitListView(PermissionRequiredMixin, ObjectListView):\n    permission_required = 'circuits.view_circuit'\n    _terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk'))\n    queryset = Circuit.objects.prefetch_related(\n        'provider', 'type', 'tenant', 'terminations__site'\n    ).annotate(\n        a_side=Subquery(_terminations.filter(term_side='A').values('site__name')[:1]),\n        z_side=Subquery(_terminations.filter(term_side='Z').values('site__name')[:1]),\n    )\n    filter = filters.CircuitFilter\n    filter_form = forms.CircuitFilterForm\n    table = tables.CircuitTable\n    template_name = 'circuits/circuit_list.html'\n\n\nclass CircuitView(PermissionRequiredMixin, View):\n    permission_required = 'circuits.view_circuit'\n\n    def get(self, request, pk):\n\n        circuit = get_object_or_404(Circuit.objects.prefetch_related('provider', 'type', 'tenant__group'), pk=pk)\n        termination_a = CircuitTermination.objects.prefetch_related(\n            'site__region', 'connected_endpoint__device'\n        ).filter(\n            circuit=circuit, term_side=TERM_SIDE_A\n        ).first()\n        termination_z = CircuitTermination.objects.prefetch_related(\n            'site__region', 'connected_endpoint__device'\n        ).filter(\n            circuit=circuit, term_side=TERM_SIDE_Z\n        ).first()\n\n        return render(request, 'circuits/circuit.html', {\n            'circuit': circuit,\n            'termination_a': termination_a,\n            'termination_z': termination_z,\n        })\n\n\nclass CircuitCreateView(PermissionRequiredMixin, ObjectEditView):\n    permission_required = 'circuits.add_circuit'\n    model = Circuit\n    model_form = forms.CircuitForm\n    template_name = 'circuits/circuit_edit.html'\n    default_return_url = 'circuits:circuit_list'\n\n\nclass CircuitEditView(CircuitCreateView):\n    permission_required = 'circuits.change_circuit'\n\n\nclass CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):\n    permission_required = 'circuits.delete_circuit'\n    model = Circuit\n    default_return_url = 'circuits:circuit_list'\n\n\nclass CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):\n    permission_required = 'circuits.add_circuit'\n    model_form = forms.CircuitCSVForm\n    table = tables.CircuitTable\n    default_return_url = 'circuits:circuit_list'\n\n\nclass CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):\n    permission_required = 'circuits.change_circuit'\n    queryset = Circuit.objects.prefetch_related('provider', 'type', 'tenant').prefetch_related('terminations__site')\n    filter = filters.CircuitFilter\n    table = tables.CircuitTable\n    form = forms.CircuitBulkEditForm\n    default_return_url = 'circuits:circuit_list'\n\n\nclass CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):\n    permission_required = 'circuits.delete_circuit'\n    queryset = Circuit.objects.prefetch_related('provider', 'type', 'tenant').prefetch_related('terminations__site')\n    filter = filters.CircuitFilter\n    table = tables.CircuitTable\n    default_return_url = 'circuits:circuit_list'\n\n\n@permission_required('circuits.change_circuittermination')\ndef circuit_terminations_swap(request, pk):\n\n    circuit = get_object_or_404(Circuit, pk=pk)\n    termination_a = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_A).first()\n    termination_z = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_Z).first()\n    if not termination_a and not termination_z:\n        messages.error(request, \"No terminations have been defined for circuit {}.\".format(circuit))\n        return redirect('circuits:circuit', pk=circuit.pk)\n\n    if request.method == 'POST':\n        form = ConfirmationForm(request.POST)\n        if form.is_valid():\n            if termination_a and termination_z:\n                # Use a placeholder to avoid an IntegrityError on the (circuit, term_side) unique constraint\n                with transaction.atomic():\n                    termination_a.term_side = '_'\n                    termination_a.save()\n                    termination_z.term_side = 'A'\n                    termination_z.save()\n                    termination_a.term_side = 'Z'\n                    termination_a.save()\n            elif termination_a:\n                termination_a.term_side = 'Z'\n                termination_a.save()\n            else:\n                termination_z.term_side = 'A'\n                termination_z.save()\n            messages.success(request, \"Swapped terminations for circuit {}.\".format(circuit))\n            return redirect('circuits:circuit', pk=circuit.pk)\n\n    else:\n        form = ConfirmationForm()\n\n    return render(request, 'circuits/circuit_terminations_swap.html', {\n        'circuit': circuit,\n        'termination_a': termination_a,\n        'termination_z': termination_z,\n        'form': form,\n        'panel_class': 'default',\n        'button_class': 'primary',\n        'return_url': circuit.get_absolute_url(),\n    })\n\n\n#\n# Circuit terminations\n#\n\nclass CircuitTerminationCreateView(PermissionRequiredMixin, ObjectEditView):\n    permission_required = 'circuits.add_circuittermination'\n    model = CircuitTermination\n    model_form = forms.CircuitTerminationForm\n    template_name = 'circuits/circuittermination_edit.html'\n\n    def alter_obj(self, obj, request, url_args, url_kwargs):\n        if 'circuit' in url_kwargs:\n            obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit'])\n        return obj\n\n    def get_return_url(self, request, obj):\n        return obj.circuit.get_absolute_url()\n\n\nclass CircuitTerminationEditView(CircuitTerminationCreateView):\n    permission_required = 'circuits.change_circuittermination'\n\n\nclass CircuitTerminationDeleteView(PermissionRequiredMixin, ObjectDeleteView):\n    permission_required = 'circuits.delete_circuittermination'\n    model = CircuitTermination\n", "path": "netbox/circuits/views.py"}]}