views.py 95 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087
  1. from collections import OrderedDict
  2. from django.contrib import messages
  3. from django.contrib.contenttypes.models import ContentType
  4. from django.core.paginator import EmptyPage, PageNotAnInteger
  5. from django.db import transaction
  6. from django.db.models import Prefetch
  7. from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, modelformset_factory
  8. from django.shortcuts import get_object_or_404, redirect, render
  9. from django.urls import reverse
  10. from django.utils.html import escape
  11. from django.utils.safestring import mark_safe
  12. from django.views.generic import View
  13. from circuits.models import Circuit
  14. from extras.views import ObjectConfigContextView
  15. from ipam.models import ASN, IPAddress, Prefix, Service, VLAN
  16. from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable
  17. from netbox.views import generic
  18. from utilities.forms import ConfirmationForm
  19. from utilities.paginator import EnhancedPaginator, get_paginate_count
  20. from utilities.permissions import get_permission_for_model
  21. from utilities.tables import paginate_table
  22. from utilities.utils import count_related
  23. from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin
  24. from virtualization.models import VirtualMachine
  25. from . import filtersets, forms, tables
  26. from .choices import DeviceFaceChoices
  27. from .constants import NONCONNECTABLE_IFACE_TYPES
  28. from .models import (
  29. Cable, CablePath, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
  30. DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
  31. InventoryItem, Manufacturer, Module, ModuleBay, ModuleBayTemplate, ModuleType, PathEndpoint, Platform, PowerFeed,
  32. PowerOutlet, PowerOutletTemplate, PowerPanel, PowerPort, PowerPortTemplate, Rack, Location, RackReservation,
  33. RackRole, RearPort, RearPortTemplate, Region, Site, SiteGroup, VirtualChassis,
  34. )
  35. class DeviceComponentsView(generic.ObjectChildrenView):
  36. queryset = Device.objects.all()
  37. def get_children(self, request, parent):
  38. return self.child_model.objects.restrict(request.user, 'view').filter(device=parent)
  39. def get_extra_context(self, request, instance):
  40. return {
  41. 'active_tab': f"{self.child_model._meta.verbose_name_plural.replace(' ', '-')}",
  42. }
  43. class DeviceTypeComponentsView(DeviceComponentsView):
  44. queryset = DeviceType.objects.all()
  45. template_name = 'dcim/devicetype/component_templates.html'
  46. def get_children(self, request, parent):
  47. return self.child_model.objects.restrict(request.user, 'view').filter(device_type=parent)
  48. class ModuleTypeComponentsView(DeviceComponentsView):
  49. queryset = ModuleType.objects.all()
  50. template_name = 'dcim/moduletype/component_templates.html'
  51. def get_children(self, request, parent):
  52. return self.child_model.objects.restrict(request.user, 'view').filter(module_type=parent)
  53. class BulkDisconnectView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
  54. """
  55. An extendable view for disconnection console/power/interface components in bulk.
  56. """
  57. queryset = None
  58. template_name = 'dcim/bulk_disconnect.html'
  59. def __init__(self, *args, **kwargs):
  60. super().__init__(*args, **kwargs)
  61. # Create a new Form class from ConfirmationForm
  62. class _Form(ConfirmationForm):
  63. pk = ModelMultipleChoiceField(
  64. queryset=self.queryset,
  65. widget=MultipleHiddenInput()
  66. )
  67. self.form = _Form
  68. def get_required_permission(self):
  69. return get_permission_for_model(self.queryset.model, 'change')
  70. def post(self, request):
  71. selected_objects = []
  72. return_url = self.get_return_url(request)
  73. if '_confirm' in request.POST:
  74. form = self.form(request.POST)
  75. if form.is_valid():
  76. with transaction.atomic():
  77. count = 0
  78. for obj in self.queryset.filter(pk__in=form.cleaned_data['pk']):
  79. if obj.cable is None:
  80. continue
  81. obj.cable.delete()
  82. count += 1
  83. messages.success(request, "Disconnected {} {}".format(
  84. count, self.queryset.model._meta.verbose_name_plural
  85. ))
  86. return redirect(return_url)
  87. else:
  88. form = self.form(initial={'pk': request.POST.getlist('pk')})
  89. selected_objects = self.queryset.filter(pk__in=form.initial['pk'])
  90. return render(request, self.template_name, {
  91. 'form': form,
  92. 'obj_type_plural': self.queryset.model._meta.verbose_name_plural,
  93. 'selected_objects': selected_objects,
  94. 'return_url': return_url,
  95. })
  96. #
  97. # Regions
  98. #
  99. class RegionListView(generic.ObjectListView):
  100. queryset = Region.objects.add_related_count(
  101. Region.objects.all(),
  102. Site,
  103. 'region',
  104. 'site_count',
  105. cumulative=True
  106. )
  107. filterset = filtersets.RegionFilterSet
  108. filterset_form = forms.RegionFilterForm
  109. table = tables.RegionTable
  110. class RegionView(generic.ObjectView):
  111. queryset = Region.objects.all()
  112. def get_extra_context(self, request, instance):
  113. child_regions = Region.objects.add_related_count(
  114. Region.objects.all(),
  115. Site,
  116. 'region',
  117. 'site_count',
  118. cumulative=True
  119. ).restrict(request.user, 'view').filter(
  120. parent__in=instance.get_descendants(include_self=True)
  121. )
  122. child_regions_table = tables.RegionTable(child_regions)
  123. child_regions_table.columns.hide('actions')
  124. sites = Site.objects.restrict(request.user, 'view').filter(
  125. region=instance
  126. )
  127. sites_table = tables.SiteTable(sites, exclude=('region',))
  128. paginate_table(sites_table, request)
  129. return {
  130. 'child_regions_table': child_regions_table,
  131. 'sites_table': sites_table,
  132. }
  133. class RegionEditView(generic.ObjectEditView):
  134. queryset = Region.objects.all()
  135. model_form = forms.RegionForm
  136. class RegionDeleteView(generic.ObjectDeleteView):
  137. queryset = Region.objects.all()
  138. class RegionBulkImportView(generic.BulkImportView):
  139. queryset = Region.objects.all()
  140. model_form = forms.RegionCSVForm
  141. table = tables.RegionTable
  142. class RegionBulkEditView(generic.BulkEditView):
  143. queryset = Region.objects.add_related_count(
  144. Region.objects.all(),
  145. Site,
  146. 'region',
  147. 'site_count',
  148. cumulative=True
  149. )
  150. filterset = filtersets.RegionFilterSet
  151. table = tables.RegionTable
  152. form = forms.RegionBulkEditForm
  153. class RegionBulkDeleteView(generic.BulkDeleteView):
  154. queryset = Region.objects.add_related_count(
  155. Region.objects.all(),
  156. Site,
  157. 'region',
  158. 'site_count',
  159. cumulative=True
  160. )
  161. filterset = filtersets.RegionFilterSet
  162. table = tables.RegionTable
  163. #
  164. # Site groups
  165. #
  166. class SiteGroupListView(generic.ObjectListView):
  167. queryset = SiteGroup.objects.add_related_count(
  168. SiteGroup.objects.all(),
  169. Site,
  170. 'group',
  171. 'site_count',
  172. cumulative=True
  173. )
  174. filterset = filtersets.SiteGroupFilterSet
  175. filterset_form = forms.SiteGroupFilterForm
  176. table = tables.SiteGroupTable
  177. class SiteGroupView(generic.ObjectView):
  178. queryset = SiteGroup.objects.all()
  179. def get_extra_context(self, request, instance):
  180. child_groups = SiteGroup.objects.add_related_count(
  181. SiteGroup.objects.all(),
  182. Site,
  183. 'group',
  184. 'site_count',
  185. cumulative=True
  186. ).restrict(request.user, 'view').filter(
  187. parent__in=instance.get_descendants(include_self=True)
  188. )
  189. child_groups_table = tables.SiteGroupTable(child_groups)
  190. child_groups_table.columns.hide('actions')
  191. sites = Site.objects.restrict(request.user, 'view').filter(
  192. group=instance
  193. )
  194. sites_table = tables.SiteTable(sites, exclude=('group',))
  195. paginate_table(sites_table, request)
  196. return {
  197. 'child_groups_table': child_groups_table,
  198. 'sites_table': sites_table,
  199. }
  200. class SiteGroupEditView(generic.ObjectEditView):
  201. queryset = SiteGroup.objects.all()
  202. model_form = forms.SiteGroupForm
  203. class SiteGroupDeleteView(generic.ObjectDeleteView):
  204. queryset = SiteGroup.objects.all()
  205. class SiteGroupBulkImportView(generic.BulkImportView):
  206. queryset = SiteGroup.objects.all()
  207. model_form = forms.SiteGroupCSVForm
  208. table = tables.SiteGroupTable
  209. class SiteGroupBulkEditView(generic.BulkEditView):
  210. queryset = SiteGroup.objects.add_related_count(
  211. SiteGroup.objects.all(),
  212. Site,
  213. 'group',
  214. 'site_count',
  215. cumulative=True
  216. )
  217. filterset = filtersets.SiteGroupFilterSet
  218. table = tables.SiteGroupTable
  219. form = forms.SiteGroupBulkEditForm
  220. class SiteGroupBulkDeleteView(generic.BulkDeleteView):
  221. queryset = SiteGroup.objects.add_related_count(
  222. SiteGroup.objects.all(),
  223. Site,
  224. 'group',
  225. 'site_count',
  226. cumulative=True
  227. )
  228. filterset = filtersets.SiteGroupFilterSet
  229. table = tables.SiteGroupTable
  230. #
  231. # Sites
  232. #
  233. class SiteListView(generic.ObjectListView):
  234. queryset = Site.objects.all()
  235. filterset = filtersets.SiteFilterSet
  236. filterset_form = forms.SiteFilterForm
  237. table = tables.SiteTable
  238. class SiteView(generic.ObjectView):
  239. queryset = Site.objects.prefetch_related('region', 'tenant__group')
  240. def get_extra_context(self, request, instance):
  241. stats = {
  242. 'location_count': Location.objects.restrict(request.user, 'view').filter(site=instance).count(),
  243. 'rack_count': Rack.objects.restrict(request.user, 'view').filter(site=instance).count(),
  244. 'device_count': Device.objects.restrict(request.user, 'view').filter(site=instance).count(),
  245. 'prefix_count': Prefix.objects.restrict(request.user, 'view').filter(site=instance).count(),
  246. 'vlan_count': VLAN.objects.restrict(request.user, 'view').filter(site=instance).count(),
  247. 'circuit_count': Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).count(),
  248. 'vm_count': VirtualMachine.objects.restrict(request.user, 'view').filter(cluster__site=instance).count(),
  249. }
  250. locations = Location.objects.add_related_count(
  251. Location.objects.all(),
  252. Rack,
  253. 'location',
  254. 'rack_count',
  255. cumulative=True
  256. )
  257. locations = Location.objects.add_related_count(
  258. locations,
  259. Device,
  260. 'location',
  261. 'device_count',
  262. cumulative=True
  263. ).restrict(request.user, 'view').filter(site=instance)
  264. asns = ASN.objects.restrict(request.user, 'view').filter(sites=instance)
  265. asn_count = asns.count()
  266. stats.update({'asn_count': asn_count})
  267. return {
  268. 'stats': stats,
  269. 'locations': locations,
  270. 'asns': asns,
  271. }
  272. class SiteEditView(generic.ObjectEditView):
  273. queryset = Site.objects.all()
  274. model_form = forms.SiteForm
  275. class SiteDeleteView(generic.ObjectDeleteView):
  276. queryset = Site.objects.all()
  277. class SiteBulkImportView(generic.BulkImportView):
  278. queryset = Site.objects.all()
  279. model_form = forms.SiteCSVForm
  280. table = tables.SiteTable
  281. class SiteBulkEditView(generic.BulkEditView):
  282. queryset = Site.objects.prefetch_related('region', 'tenant')
  283. filterset = filtersets.SiteFilterSet
  284. table = tables.SiteTable
  285. form = forms.SiteBulkEditForm
  286. class SiteBulkDeleteView(generic.BulkDeleteView):
  287. queryset = Site.objects.prefetch_related('region', 'tenant')
  288. filterset = filtersets.SiteFilterSet
  289. table = tables.SiteTable
  290. #
  291. # Locations
  292. #
  293. class LocationListView(generic.ObjectListView):
  294. queryset = Location.objects.add_related_count(
  295. Location.objects.add_related_count(
  296. Location.objects.all(),
  297. Device,
  298. 'location',
  299. 'device_count',
  300. cumulative=True
  301. ),
  302. Rack,
  303. 'location',
  304. 'rack_count',
  305. cumulative=True
  306. )
  307. filterset = filtersets.LocationFilterSet
  308. filterset_form = forms.LocationFilterForm
  309. table = tables.LocationTable
  310. class LocationView(generic.ObjectView):
  311. queryset = Location.objects.all()
  312. def get_extra_context(self, request, instance):
  313. location_ids = instance.get_descendants(include_self=True).values_list('pk', flat=True)
  314. rack_count = Rack.objects.filter(location__in=location_ids).count()
  315. device_count = Device.objects.filter(location__in=location_ids).count()
  316. child_locations = Location.objects.add_related_count(
  317. Location.objects.add_related_count(
  318. Location.objects.all(),
  319. Device,
  320. 'location',
  321. 'device_count',
  322. cumulative=True
  323. ),
  324. Rack,
  325. 'location',
  326. 'rack_count',
  327. cumulative=True
  328. ).filter(pk__in=location_ids).exclude(pk=instance.pk)
  329. child_locations_table = tables.LocationTable(child_locations)
  330. paginate_table(child_locations_table, request)
  331. return {
  332. 'rack_count': rack_count,
  333. 'device_count': device_count,
  334. 'child_locations_table': child_locations_table,
  335. }
  336. class LocationEditView(generic.ObjectEditView):
  337. queryset = Location.objects.all()
  338. model_form = forms.LocationForm
  339. class LocationDeleteView(generic.ObjectDeleteView):
  340. queryset = Location.objects.all()
  341. class LocationBulkImportView(generic.BulkImportView):
  342. queryset = Location.objects.all()
  343. model_form = forms.LocationCSVForm
  344. table = tables.LocationTable
  345. class LocationBulkEditView(generic.BulkEditView):
  346. queryset = Location.objects.add_related_count(
  347. Location.objects.all(),
  348. Rack,
  349. 'location',
  350. 'rack_count',
  351. cumulative=True
  352. ).prefetch_related('site')
  353. filterset = filtersets.LocationFilterSet
  354. table = tables.LocationTable
  355. form = forms.LocationBulkEditForm
  356. class LocationBulkDeleteView(generic.BulkDeleteView):
  357. queryset = Location.objects.add_related_count(
  358. Location.objects.all(),
  359. Rack,
  360. 'location',
  361. 'rack_count',
  362. cumulative=True
  363. ).prefetch_related('site')
  364. filterset = filtersets.LocationFilterSet
  365. table = tables.LocationTable
  366. #
  367. # Rack roles
  368. #
  369. class RackRoleListView(generic.ObjectListView):
  370. queryset = RackRole.objects.annotate(
  371. rack_count=count_related(Rack, 'role')
  372. )
  373. filterset = filtersets.RackRoleFilterSet
  374. filterset_form = forms.RackRoleFilterForm
  375. table = tables.RackRoleTable
  376. class RackRoleView(generic.ObjectView):
  377. queryset = RackRole.objects.all()
  378. def get_extra_context(self, request, instance):
  379. racks = Rack.objects.restrict(request.user, 'view').filter(
  380. role=instance
  381. )
  382. racks_table = tables.RackTable(racks, exclude=('role', 'get_utilization', 'get_power_utilization'))
  383. paginate_table(racks_table, request)
  384. return {
  385. 'racks_table': racks_table,
  386. }
  387. class RackRoleEditView(generic.ObjectEditView):
  388. queryset = RackRole.objects.all()
  389. model_form = forms.RackRoleForm
  390. class RackRoleDeleteView(generic.ObjectDeleteView):
  391. queryset = RackRole.objects.all()
  392. class RackRoleBulkImportView(generic.BulkImportView):
  393. queryset = RackRole.objects.all()
  394. model_form = forms.RackRoleCSVForm
  395. table = tables.RackRoleTable
  396. class RackRoleBulkEditView(generic.BulkEditView):
  397. queryset = RackRole.objects.annotate(
  398. rack_count=count_related(Rack, 'role')
  399. )
  400. filterset = filtersets.RackRoleFilterSet
  401. table = tables.RackRoleTable
  402. form = forms.RackRoleBulkEditForm
  403. class RackRoleBulkDeleteView(generic.BulkDeleteView):
  404. queryset = RackRole.objects.annotate(
  405. rack_count=count_related(Rack, 'role')
  406. )
  407. table = tables.RackRoleTable
  408. #
  409. # Racks
  410. #
  411. class RackListView(generic.ObjectListView):
  412. queryset = Rack.objects.prefetch_related(
  413. 'site', 'location', 'tenant', 'role', 'devices__device_type'
  414. ).annotate(
  415. device_count=count_related(Device, 'rack')
  416. )
  417. filterset = filtersets.RackFilterSet
  418. filterset_form = forms.RackFilterForm
  419. table = tables.RackTable
  420. class RackElevationListView(generic.ObjectListView):
  421. """
  422. Display a set of rack elevations side-by-side.
  423. """
  424. queryset = Rack.objects.prefetch_related('role')
  425. def get(self, request):
  426. racks = filtersets.RackFilterSet(request.GET, self.queryset).qs
  427. total_count = racks.count()
  428. # Determine ordering
  429. reverse = bool(request.GET.get('reverse', False))
  430. if reverse:
  431. racks = racks.reverse()
  432. # Pagination
  433. per_page = get_paginate_count(request)
  434. page_number = request.GET.get('page', 1)
  435. paginator = EnhancedPaginator(racks, per_page)
  436. try:
  437. page = paginator.page(page_number)
  438. except PageNotAnInteger:
  439. page = paginator.page(1)
  440. except EmptyPage:
  441. page = paginator.page(paginator.num_pages)
  442. # Determine rack face
  443. rack_face = request.GET.get('face', DeviceFaceChoices.FACE_FRONT)
  444. if rack_face not in DeviceFaceChoices.values():
  445. rack_face = DeviceFaceChoices.FACE_FRONT
  446. return render(request, 'dcim/rack_elevation_list.html', {
  447. 'paginator': paginator,
  448. 'page': page,
  449. 'total_count': total_count,
  450. 'reverse': reverse,
  451. 'rack_face': rack_face,
  452. 'filter_form': forms.RackElevationFilterForm(request.GET),
  453. })
  454. class RackView(generic.ObjectView):
  455. queryset = Rack.objects.prefetch_related('site__region', 'tenant__group', 'location', 'role')
  456. def get_extra_context(self, request, instance):
  457. # Get 0U devices located within the rack
  458. nonracked_devices = Device.objects.filter(
  459. rack=instance,
  460. position__isnull=True,
  461. parent_bay__isnull=True
  462. ).prefetch_related('device_type__manufacturer')
  463. peer_racks = Rack.objects.restrict(request.user, 'view').filter(site=instance.site)
  464. if instance.location:
  465. peer_racks = peer_racks.filter(location=instance.location)
  466. else:
  467. peer_racks = peer_racks.filter(location__isnull=True)
  468. next_rack = peer_racks.filter(name__gt=instance.name).order_by('name').first()
  469. prev_rack = peer_racks.filter(name__lt=instance.name).order_by('-name').first()
  470. reservations = RackReservation.objects.restrict(request.user, 'view').filter(rack=instance)
  471. power_feeds = PowerFeed.objects.restrict(request.user, 'view').filter(rack=instance).prefetch_related(
  472. 'power_panel'
  473. )
  474. device_count = Device.objects.restrict(request.user, 'view').filter(rack=instance).count()
  475. return {
  476. 'device_count': device_count,
  477. 'reservations': reservations,
  478. 'power_feeds': power_feeds,
  479. 'nonracked_devices': nonracked_devices,
  480. 'next_rack': next_rack,
  481. 'prev_rack': prev_rack,
  482. }
  483. class RackEditView(generic.ObjectEditView):
  484. queryset = Rack.objects.all()
  485. model_form = forms.RackForm
  486. template_name = 'dcim/rack_edit.html'
  487. class RackDeleteView(generic.ObjectDeleteView):
  488. queryset = Rack.objects.all()
  489. class RackBulkImportView(generic.BulkImportView):
  490. queryset = Rack.objects.all()
  491. model_form = forms.RackCSVForm
  492. table = tables.RackTable
  493. class RackBulkEditView(generic.BulkEditView):
  494. queryset = Rack.objects.prefetch_related('site', 'location', 'tenant', 'role')
  495. filterset = filtersets.RackFilterSet
  496. table = tables.RackTable
  497. form = forms.RackBulkEditForm
  498. class RackBulkDeleteView(generic.BulkDeleteView):
  499. queryset = Rack.objects.prefetch_related('site', 'location', 'tenant', 'role')
  500. filterset = filtersets.RackFilterSet
  501. table = tables.RackTable
  502. #
  503. # Rack reservations
  504. #
  505. class RackReservationListView(generic.ObjectListView):
  506. queryset = RackReservation.objects.all()
  507. filterset = filtersets.RackReservationFilterSet
  508. filterset_form = forms.RackReservationFilterForm
  509. table = tables.RackReservationTable
  510. class RackReservationView(generic.ObjectView):
  511. queryset = RackReservation.objects.prefetch_related('rack')
  512. class RackReservationEditView(generic.ObjectEditView):
  513. queryset = RackReservation.objects.all()
  514. model_form = forms.RackReservationForm
  515. def alter_object(self, obj, request, args, kwargs):
  516. if not obj.pk:
  517. if 'rack' in request.GET:
  518. obj.rack = get_object_or_404(Rack, pk=request.GET.get('rack'))
  519. obj.user = request.user
  520. return obj
  521. class RackReservationDeleteView(generic.ObjectDeleteView):
  522. queryset = RackReservation.objects.all()
  523. class RackReservationImportView(generic.BulkImportView):
  524. queryset = RackReservation.objects.all()
  525. model_form = forms.RackReservationCSVForm
  526. table = tables.RackReservationTable
  527. def _save_obj(self, obj_form, request):
  528. """
  529. Assign the currently authenticated user to the RackReservation.
  530. """
  531. instance = obj_form.save(commit=False)
  532. instance.user = request.user
  533. instance.save()
  534. return instance
  535. class RackReservationBulkEditView(generic.BulkEditView):
  536. queryset = RackReservation.objects.prefetch_related('rack', 'user')
  537. filterset = filtersets.RackReservationFilterSet
  538. table = tables.RackReservationTable
  539. form = forms.RackReservationBulkEditForm
  540. class RackReservationBulkDeleteView(generic.BulkDeleteView):
  541. queryset = RackReservation.objects.prefetch_related('rack', 'user')
  542. filterset = filtersets.RackReservationFilterSet
  543. table = tables.RackReservationTable
  544. #
  545. # Manufacturers
  546. #
  547. class ManufacturerListView(generic.ObjectListView):
  548. queryset = Manufacturer.objects.annotate(
  549. devicetype_count=count_related(DeviceType, 'manufacturer'),
  550. inventoryitem_count=count_related(InventoryItem, 'manufacturer'),
  551. platform_count=count_related(Platform, 'manufacturer')
  552. )
  553. filterset = filtersets.ManufacturerFilterSet
  554. filterset_form = forms.ManufacturerFilterForm
  555. table = tables.ManufacturerTable
  556. class ManufacturerView(generic.ObjectView):
  557. queryset = Manufacturer.objects.all()
  558. def get_extra_context(self, request, instance):
  559. devicetypes = DeviceType.objects.restrict(request.user, 'view').filter(
  560. manufacturer=instance
  561. ).annotate(
  562. instance_count=count_related(Device, 'device_type')
  563. )
  564. inventory_items = InventoryItem.objects.restrict(request.user, 'view').filter(
  565. manufacturer=instance
  566. )
  567. devicetypes_table = tables.DeviceTypeTable(devicetypes, exclude=('manufacturer',))
  568. paginate_table(devicetypes_table, request)
  569. return {
  570. 'devicetypes_table': devicetypes_table,
  571. 'inventory_item_count': inventory_items.count(),
  572. }
  573. class ManufacturerEditView(generic.ObjectEditView):
  574. queryset = Manufacturer.objects.all()
  575. model_form = forms.ManufacturerForm
  576. class ManufacturerDeleteView(generic.ObjectDeleteView):
  577. queryset = Manufacturer.objects.all()
  578. class ManufacturerBulkImportView(generic.BulkImportView):
  579. queryset = Manufacturer.objects.all()
  580. model_form = forms.ManufacturerCSVForm
  581. table = tables.ManufacturerTable
  582. class ManufacturerBulkEditView(generic.BulkEditView):
  583. queryset = Manufacturer.objects.annotate(
  584. devicetype_count=count_related(DeviceType, 'manufacturer')
  585. )
  586. filterset = filtersets.ManufacturerFilterSet
  587. table = tables.ManufacturerTable
  588. form = forms.ManufacturerBulkEditForm
  589. class ManufacturerBulkDeleteView(generic.BulkDeleteView):
  590. queryset = Manufacturer.objects.annotate(
  591. devicetype_count=count_related(DeviceType, 'manufacturer')
  592. )
  593. table = tables.ManufacturerTable
  594. #
  595. # Device types
  596. #
  597. class DeviceTypeListView(generic.ObjectListView):
  598. queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(
  599. instance_count=count_related(Device, 'device_type')
  600. )
  601. filterset = filtersets.DeviceTypeFilterSet
  602. filterset_form = forms.DeviceTypeFilterForm
  603. table = tables.DeviceTypeTable
  604. class DeviceTypeView(generic.ObjectView):
  605. queryset = DeviceType.objects.prefetch_related('manufacturer')
  606. def get_extra_context(self, request, instance):
  607. instance_count = Device.objects.restrict(request.user).filter(device_type=instance).count()
  608. return {
  609. 'instance_count': instance_count,
  610. 'active_tab': 'devicetype',
  611. }
  612. class DeviceTypeConsolePortsView(DeviceTypeComponentsView):
  613. child_model = ConsolePortTemplate
  614. table = tables.ConsolePortTemplateTable
  615. filterset = filtersets.ConsolePortTemplateFilterSet
  616. class DeviceTypeConsoleServerPortsView(DeviceTypeComponentsView):
  617. child_model = ConsoleServerPortTemplate
  618. table = tables.ConsoleServerPortTemplateTable
  619. filterset = filtersets.ConsoleServerPortTemplateFilterSet
  620. class DeviceTypePowerPortsView(DeviceTypeComponentsView):
  621. child_model = PowerPortTemplate
  622. table = tables.PowerPortTemplateTable
  623. filterset = filtersets.PowerPortTemplateFilterSet
  624. class DeviceTypePowerOutletsView(DeviceTypeComponentsView):
  625. child_model = PowerOutletTemplate
  626. table = tables.PowerOutletTemplateTable
  627. filterset = filtersets.PowerOutletTemplateFilterSet
  628. class DeviceTypeInterfacesView(DeviceTypeComponentsView):
  629. child_model = InterfaceTemplate
  630. table = tables.InterfaceTemplateTable
  631. filterset = filtersets.InterfaceTemplateFilterSet
  632. class DeviceTypeFrontPortsView(DeviceTypeComponentsView):
  633. child_model = FrontPortTemplate
  634. table = tables.FrontPortTemplateTable
  635. filterset = filtersets.FrontPortTemplateFilterSet
  636. class DeviceTypeRearPortsView(DeviceTypeComponentsView):
  637. child_model = RearPortTemplate
  638. table = tables.RearPortTemplateTable
  639. filterset = filtersets.RearPortTemplateFilterSet
  640. class DeviceTypeModuleBaysView(DeviceTypeComponentsView):
  641. child_model = ModuleBayTemplate
  642. table = tables.ModuleBayTemplateTable
  643. filterset = filtersets.ModuleBayTemplateFilterSet
  644. class DeviceTypeDeviceBaysView(DeviceTypeComponentsView):
  645. child_model = DeviceBayTemplate
  646. table = tables.DeviceBayTemplateTable
  647. filterset = filtersets.DeviceBayTemplateFilterSet
  648. class DeviceTypeEditView(generic.ObjectEditView):
  649. queryset = DeviceType.objects.all()
  650. model_form = forms.DeviceTypeForm
  651. class DeviceTypeDeleteView(generic.ObjectDeleteView):
  652. queryset = DeviceType.objects.all()
  653. class DeviceTypeImportView(generic.ObjectImportView):
  654. additional_permissions = [
  655. 'dcim.add_devicetype',
  656. 'dcim.add_consoleporttemplate',
  657. 'dcim.add_consoleserverporttemplate',
  658. 'dcim.add_powerporttemplate',
  659. 'dcim.add_poweroutlettemplate',
  660. 'dcim.add_interfacetemplate',
  661. 'dcim.add_frontporttemplate',
  662. 'dcim.add_rearporttemplate',
  663. 'dcim.add_modulebaytemplate',
  664. 'dcim.add_devicebaytemplate',
  665. ]
  666. queryset = DeviceType.objects.all()
  667. model_form = forms.DeviceTypeImportForm
  668. related_object_forms = OrderedDict((
  669. ('console-ports', forms.ConsolePortTemplateImportForm),
  670. ('console-server-ports', forms.ConsoleServerPortTemplateImportForm),
  671. ('power-ports', forms.PowerPortTemplateImportForm),
  672. ('power-outlets', forms.PowerOutletTemplateImportForm),
  673. ('interfaces', forms.InterfaceTemplateImportForm),
  674. ('rear-ports', forms.RearPortTemplateImportForm),
  675. ('front-ports', forms.FrontPortTemplateImportForm),
  676. ('module-bays', forms.ModuleBayTemplateImportForm),
  677. ('device-bays', forms.DeviceBayTemplateImportForm),
  678. ))
  679. def prep_related_object_data(self, parent, data):
  680. data.update({'device_type': parent})
  681. return data
  682. class DeviceTypeBulkEditView(generic.BulkEditView):
  683. queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(
  684. instance_count=count_related(Device, 'device_type')
  685. )
  686. filterset = filtersets.DeviceTypeFilterSet
  687. table = tables.DeviceTypeTable
  688. form = forms.DeviceTypeBulkEditForm
  689. class DeviceTypeBulkDeleteView(generic.BulkDeleteView):
  690. queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(
  691. instance_count=count_related(Device, 'device_type')
  692. )
  693. filterset = filtersets.DeviceTypeFilterSet
  694. table = tables.DeviceTypeTable
  695. #
  696. # Module types
  697. #
  698. class ModuleTypeListView(generic.ObjectListView):
  699. queryset = ModuleType.objects.prefetch_related('manufacturer').annotate(
  700. # instance_count=count_related(Module, 'module_type')
  701. )
  702. filterset = filtersets.ModuleTypeFilterSet
  703. filterset_form = forms.ModuleTypeFilterForm
  704. table = tables.ModuleTypeTable
  705. class ModuleTypeView(generic.ObjectView):
  706. queryset = ModuleType.objects.prefetch_related('manufacturer')
  707. def get_extra_context(self, request, instance):
  708. # instance_count = Module.objects.restrict(request.user).filter(device_type=instance).count()
  709. return {
  710. # 'instance_count': instance_count,
  711. 'active_tab': 'moduletype',
  712. }
  713. class ModuleTypeConsolePortsView(ModuleTypeComponentsView):
  714. child_model = ConsolePortTemplate
  715. table = tables.ConsolePortTemplateTable
  716. filterset = filtersets.ConsolePortTemplateFilterSet
  717. class ModuleTypeConsoleServerPortsView(ModuleTypeComponentsView):
  718. child_model = ConsoleServerPortTemplate
  719. table = tables.ConsoleServerPortTemplateTable
  720. filterset = filtersets.ConsoleServerPortTemplateFilterSet
  721. class ModuleTypePowerPortsView(ModuleTypeComponentsView):
  722. child_model = PowerPortTemplate
  723. table = tables.PowerPortTemplateTable
  724. filterset = filtersets.PowerPortTemplateFilterSet
  725. class ModuleTypePowerOutletsView(ModuleTypeComponentsView):
  726. child_model = PowerOutletTemplate
  727. table = tables.PowerOutletTemplateTable
  728. filterset = filtersets.PowerOutletTemplateFilterSet
  729. class ModuleTypeInterfacesView(ModuleTypeComponentsView):
  730. child_model = InterfaceTemplate
  731. table = tables.InterfaceTemplateTable
  732. filterset = filtersets.InterfaceTemplateFilterSet
  733. class ModuleTypeFrontPortsView(ModuleTypeComponentsView):
  734. child_model = FrontPortTemplate
  735. table = tables.FrontPortTemplateTable
  736. filterset = filtersets.FrontPortTemplateFilterSet
  737. class ModuleTypeRearPortsView(ModuleTypeComponentsView):
  738. child_model = RearPortTemplate
  739. table = tables.RearPortTemplateTable
  740. filterset = filtersets.RearPortTemplateFilterSet
  741. class ModuleTypeEditView(generic.ObjectEditView):
  742. queryset = ModuleType.objects.all()
  743. model_form = forms.ModuleTypeForm
  744. class ModuleTypeDeleteView(generic.ObjectDeleteView):
  745. queryset = ModuleType.objects.all()
  746. class ModuleTypeImportView(generic.ObjectImportView):
  747. additional_permissions = [
  748. 'dcim.add_moduletype',
  749. 'dcim.add_consoleporttemplate',
  750. 'dcim.add_consoleserverporttemplate',
  751. 'dcim.add_powerporttemplate',
  752. 'dcim.add_poweroutlettemplate',
  753. 'dcim.add_interfacetemplate',
  754. 'dcim.add_frontporttemplate',
  755. 'dcim.add_rearporttemplate',
  756. ]
  757. queryset = ModuleType.objects.all()
  758. model_form = forms.ModuleTypeImportForm
  759. related_object_forms = OrderedDict((
  760. ('console-ports', forms.ConsolePortTemplateImportForm),
  761. ('console-server-ports', forms.ConsoleServerPortTemplateImportForm),
  762. ('power-ports', forms.PowerPortTemplateImportForm),
  763. ('power-outlets', forms.PowerOutletTemplateImportForm),
  764. ('interfaces', forms.InterfaceTemplateImportForm),
  765. ('rear-ports', forms.RearPortTemplateImportForm),
  766. ('front-ports', forms.FrontPortTemplateImportForm),
  767. ))
  768. def prep_related_object_data(self, parent, data):
  769. data.update({'module_type': parent})
  770. return data
  771. class ModuleTypeBulkEditView(generic.BulkEditView):
  772. queryset = ModuleType.objects.prefetch_related('manufacturer').annotate(
  773. # instance_count=count_related(Module, 'module_type')
  774. )
  775. filterset = filtersets.ModuleTypeFilterSet
  776. table = tables.ModuleTypeTable
  777. form = forms.ModuleTypeBulkEditForm
  778. class ModuleTypeBulkDeleteView(generic.BulkDeleteView):
  779. queryset = ModuleType.objects.prefetch_related('manufacturer').annotate(
  780. # instance_count=count_related(Module, 'module_type')
  781. )
  782. filterset = filtersets.ModuleTypeFilterSet
  783. table = tables.ModuleTypeTable
  784. #
  785. # Console port templates
  786. #
  787. class ConsolePortTemplateCreateView(generic.ComponentCreateView):
  788. queryset = ConsolePortTemplate.objects.all()
  789. form = forms.ConsolePortTemplateCreateForm
  790. model_form = forms.ConsolePortTemplateForm
  791. class ConsolePortTemplateEditView(generic.ObjectEditView):
  792. queryset = ConsolePortTemplate.objects.all()
  793. model_form = forms.ConsolePortTemplateForm
  794. class ConsolePortTemplateDeleteView(generic.ObjectDeleteView):
  795. queryset = ConsolePortTemplate.objects.all()
  796. class ConsolePortTemplateBulkEditView(generic.BulkEditView):
  797. queryset = ConsolePortTemplate.objects.all()
  798. table = tables.ConsolePortTemplateTable
  799. form = forms.ConsolePortTemplateBulkEditForm
  800. class ConsolePortTemplateBulkRenameView(generic.BulkRenameView):
  801. queryset = ConsolePortTemplate.objects.all()
  802. class ConsolePortTemplateBulkDeleteView(generic.BulkDeleteView):
  803. queryset = ConsolePortTemplate.objects.all()
  804. table = tables.ConsolePortTemplateTable
  805. #
  806. # Console server port templates
  807. #
  808. class ConsoleServerPortTemplateCreateView(generic.ComponentCreateView):
  809. queryset = ConsoleServerPortTemplate.objects.all()
  810. form = forms.ConsoleServerPortTemplateCreateForm
  811. model_form = forms.ConsoleServerPortTemplateForm
  812. class ConsoleServerPortTemplateEditView(generic.ObjectEditView):
  813. queryset = ConsoleServerPortTemplate.objects.all()
  814. model_form = forms.ConsoleServerPortTemplateForm
  815. class ConsoleServerPortTemplateDeleteView(generic.ObjectDeleteView):
  816. queryset = ConsoleServerPortTemplate.objects.all()
  817. class ConsoleServerPortTemplateBulkEditView(generic.BulkEditView):
  818. queryset = ConsoleServerPortTemplate.objects.all()
  819. table = tables.ConsoleServerPortTemplateTable
  820. form = forms.ConsoleServerPortTemplateBulkEditForm
  821. class ConsoleServerPortTemplateBulkRenameView(generic.BulkRenameView):
  822. queryset = ConsoleServerPortTemplate.objects.all()
  823. class ConsoleServerPortTemplateBulkDeleteView(generic.BulkDeleteView):
  824. queryset = ConsoleServerPortTemplate.objects.all()
  825. table = tables.ConsoleServerPortTemplateTable
  826. #
  827. # Power port templates
  828. #
  829. class PowerPortTemplateCreateView(generic.ComponentCreateView):
  830. queryset = PowerPortTemplate.objects.all()
  831. form = forms.PowerPortTemplateCreateForm
  832. model_form = forms.PowerPortTemplateForm
  833. class PowerPortTemplateEditView(generic.ObjectEditView):
  834. queryset = PowerPortTemplate.objects.all()
  835. model_form = forms.PowerPortTemplateForm
  836. class PowerPortTemplateDeleteView(generic.ObjectDeleteView):
  837. queryset = PowerPortTemplate.objects.all()
  838. class PowerPortTemplateBulkEditView(generic.BulkEditView):
  839. queryset = PowerPortTemplate.objects.all()
  840. table = tables.PowerPortTemplateTable
  841. form = forms.PowerPortTemplateBulkEditForm
  842. class PowerPortTemplateBulkRenameView(generic.BulkRenameView):
  843. queryset = PowerPortTemplate.objects.all()
  844. class PowerPortTemplateBulkDeleteView(generic.BulkDeleteView):
  845. queryset = PowerPortTemplate.objects.all()
  846. table = tables.PowerPortTemplateTable
  847. #
  848. # Power outlet templates
  849. #
  850. class PowerOutletTemplateCreateView(generic.ComponentCreateView):
  851. queryset = PowerOutletTemplate.objects.all()
  852. form = forms.PowerOutletTemplateCreateForm
  853. model_form = forms.PowerOutletTemplateForm
  854. class PowerOutletTemplateEditView(generic.ObjectEditView):
  855. queryset = PowerOutletTemplate.objects.all()
  856. model_form = forms.PowerOutletTemplateForm
  857. class PowerOutletTemplateDeleteView(generic.ObjectDeleteView):
  858. queryset = PowerOutletTemplate.objects.all()
  859. class PowerOutletTemplateBulkEditView(generic.BulkEditView):
  860. queryset = PowerOutletTemplate.objects.all()
  861. table = tables.PowerOutletTemplateTable
  862. form = forms.PowerOutletTemplateBulkEditForm
  863. class PowerOutletTemplateBulkRenameView(generic.BulkRenameView):
  864. queryset = PowerOutletTemplate.objects.all()
  865. class PowerOutletTemplateBulkDeleteView(generic.BulkDeleteView):
  866. queryset = PowerOutletTemplate.objects.all()
  867. table = tables.PowerOutletTemplateTable
  868. #
  869. # Interface templates
  870. #
  871. class InterfaceTemplateCreateView(generic.ComponentCreateView):
  872. queryset = InterfaceTemplate.objects.all()
  873. form = forms.InterfaceTemplateCreateForm
  874. model_form = forms.InterfaceTemplateForm
  875. class InterfaceTemplateEditView(generic.ObjectEditView):
  876. queryset = InterfaceTemplate.objects.all()
  877. model_form = forms.InterfaceTemplateForm
  878. class InterfaceTemplateDeleteView(generic.ObjectDeleteView):
  879. queryset = InterfaceTemplate.objects.all()
  880. class InterfaceTemplateBulkEditView(generic.BulkEditView):
  881. queryset = InterfaceTemplate.objects.all()
  882. table = tables.InterfaceTemplateTable
  883. form = forms.InterfaceTemplateBulkEditForm
  884. class InterfaceTemplateBulkRenameView(generic.BulkRenameView):
  885. queryset = InterfaceTemplate.objects.all()
  886. class InterfaceTemplateBulkDeleteView(generic.BulkDeleteView):
  887. queryset = InterfaceTemplate.objects.all()
  888. table = tables.InterfaceTemplateTable
  889. #
  890. # Front port templates
  891. #
  892. class FrontPortTemplateCreateView(generic.ComponentCreateView):
  893. queryset = FrontPortTemplate.objects.all()
  894. form = forms.FrontPortTemplateCreateForm
  895. model_form = forms.FrontPortTemplateForm
  896. class FrontPortTemplateEditView(generic.ObjectEditView):
  897. queryset = FrontPortTemplate.objects.all()
  898. model_form = forms.FrontPortTemplateForm
  899. class FrontPortTemplateDeleteView(generic.ObjectDeleteView):
  900. queryset = FrontPortTemplate.objects.all()
  901. class FrontPortTemplateBulkEditView(generic.BulkEditView):
  902. queryset = FrontPortTemplate.objects.all()
  903. table = tables.FrontPortTemplateTable
  904. form = forms.FrontPortTemplateBulkEditForm
  905. class FrontPortTemplateBulkRenameView(generic.BulkRenameView):
  906. queryset = FrontPortTemplate.objects.all()
  907. class FrontPortTemplateBulkDeleteView(generic.BulkDeleteView):
  908. queryset = FrontPortTemplate.objects.all()
  909. table = tables.FrontPortTemplateTable
  910. #
  911. # Rear port templates
  912. #
  913. class RearPortTemplateCreateView(generic.ComponentCreateView):
  914. queryset = RearPortTemplate.objects.all()
  915. form = forms.RearPortTemplateCreateForm
  916. model_form = forms.RearPortTemplateForm
  917. class RearPortTemplateEditView(generic.ObjectEditView):
  918. queryset = RearPortTemplate.objects.all()
  919. model_form = forms.RearPortTemplateForm
  920. class RearPortTemplateDeleteView(generic.ObjectDeleteView):
  921. queryset = RearPortTemplate.objects.all()
  922. class RearPortTemplateBulkEditView(generic.BulkEditView):
  923. queryset = RearPortTemplate.objects.all()
  924. table = tables.RearPortTemplateTable
  925. form = forms.RearPortTemplateBulkEditForm
  926. class RearPortTemplateBulkRenameView(generic.BulkRenameView):
  927. queryset = RearPortTemplate.objects.all()
  928. class RearPortTemplateBulkDeleteView(generic.BulkDeleteView):
  929. queryset = RearPortTemplate.objects.all()
  930. table = tables.RearPortTemplateTable
  931. #
  932. # Module bay templates
  933. #
  934. class ModuleBayTemplateCreateView(generic.ComponentCreateView):
  935. queryset = ModuleBayTemplate.objects.all()
  936. form = forms.ModuleBayTemplateCreateForm
  937. model_form = forms.ModuleBayTemplateForm
  938. class ModuleBayTemplateEditView(generic.ObjectEditView):
  939. queryset = ModuleBayTemplate.objects.all()
  940. model_form = forms.ModuleBayTemplateForm
  941. class ModuleBayTemplateDeleteView(generic.ObjectDeleteView):
  942. queryset = ModuleBayTemplate.objects.all()
  943. class ModuleBayTemplateBulkEditView(generic.BulkEditView):
  944. queryset = ModuleBayTemplate.objects.all()
  945. table = tables.ModuleBayTemplateTable
  946. form = forms.ModuleBayTemplateBulkEditForm
  947. class ModuleBayTemplateBulkRenameView(generic.BulkRenameView):
  948. queryset = ModuleBayTemplate.objects.all()
  949. class ModuleBayTemplateBulkDeleteView(generic.BulkDeleteView):
  950. queryset = ModuleBayTemplate.objects.all()
  951. table = tables.ModuleBayTemplateTable
  952. #
  953. # Device bay templates
  954. #
  955. class DeviceBayTemplateCreateView(generic.ComponentCreateView):
  956. queryset = DeviceBayTemplate.objects.all()
  957. form = forms.DeviceBayTemplateCreateForm
  958. model_form = forms.DeviceBayTemplateForm
  959. class DeviceBayTemplateEditView(generic.ObjectEditView):
  960. queryset = DeviceBayTemplate.objects.all()
  961. model_form = forms.DeviceBayTemplateForm
  962. class DeviceBayTemplateDeleteView(generic.ObjectDeleteView):
  963. queryset = DeviceBayTemplate.objects.all()
  964. class DeviceBayTemplateBulkEditView(generic.BulkEditView):
  965. queryset = DeviceBayTemplate.objects.all()
  966. table = tables.DeviceBayTemplateTable
  967. form = forms.DeviceBayTemplateBulkEditForm
  968. class DeviceBayTemplateBulkRenameView(generic.BulkRenameView):
  969. queryset = DeviceBayTemplate.objects.all()
  970. class DeviceBayTemplateBulkDeleteView(generic.BulkDeleteView):
  971. queryset = DeviceBayTemplate.objects.all()
  972. table = tables.DeviceBayTemplateTable
  973. #
  974. # Device roles
  975. #
  976. class DeviceRoleListView(generic.ObjectListView):
  977. queryset = DeviceRole.objects.annotate(
  978. device_count=count_related(Device, 'device_role'),
  979. vm_count=count_related(VirtualMachine, 'role')
  980. )
  981. filterset = filtersets.DeviceRoleFilterSet
  982. filterset_form = forms.DeviceRoleFilterForm
  983. table = tables.DeviceRoleTable
  984. class DeviceRoleView(generic.ObjectView):
  985. queryset = DeviceRole.objects.all()
  986. def get_extra_context(self, request, instance):
  987. devices = Device.objects.restrict(request.user, 'view').filter(
  988. device_role=instance
  989. )
  990. devices_table = tables.DeviceTable(devices, exclude=('device_role',))
  991. paginate_table(devices_table, request)
  992. return {
  993. 'devices_table': devices_table,
  994. 'device_count': Device.objects.filter(device_role=instance).count(),
  995. 'virtualmachine_count': VirtualMachine.objects.filter(role=instance).count(),
  996. }
  997. class DeviceRoleEditView(generic.ObjectEditView):
  998. queryset = DeviceRole.objects.all()
  999. model_form = forms.DeviceRoleForm
  1000. class DeviceRoleDeleteView(generic.ObjectDeleteView):
  1001. queryset = DeviceRole.objects.all()
  1002. class DeviceRoleBulkImportView(generic.BulkImportView):
  1003. queryset = DeviceRole.objects.all()
  1004. model_form = forms.DeviceRoleCSVForm
  1005. table = tables.DeviceRoleTable
  1006. class DeviceRoleBulkEditView(generic.BulkEditView):
  1007. queryset = DeviceRole.objects.annotate(
  1008. device_count=count_related(Device, 'device_role'),
  1009. vm_count=count_related(VirtualMachine, 'role')
  1010. )
  1011. filterset = filtersets.DeviceRoleFilterSet
  1012. table = tables.DeviceRoleTable
  1013. form = forms.DeviceRoleBulkEditForm
  1014. class DeviceRoleBulkDeleteView(generic.BulkDeleteView):
  1015. queryset = DeviceRole.objects.annotate(
  1016. device_count=count_related(Device, 'device_role'),
  1017. vm_count=count_related(VirtualMachine, 'role')
  1018. )
  1019. table = tables.DeviceRoleTable
  1020. #
  1021. # Platforms
  1022. #
  1023. class PlatformListView(generic.ObjectListView):
  1024. queryset = Platform.objects.annotate(
  1025. device_count=count_related(Device, 'platform'),
  1026. vm_count=count_related(VirtualMachine, 'platform')
  1027. )
  1028. table = tables.PlatformTable
  1029. filterset = filtersets.PlatformFilterSet
  1030. filterset_form = forms.PlatformFilterForm
  1031. class PlatformView(generic.ObjectView):
  1032. queryset = Platform.objects.all()
  1033. def get_extra_context(self, request, instance):
  1034. devices = Device.objects.restrict(request.user, 'view').filter(
  1035. platform=instance
  1036. )
  1037. devices_table = tables.DeviceTable(devices, exclude=('platform',))
  1038. paginate_table(devices_table, request)
  1039. return {
  1040. 'devices_table': devices_table,
  1041. 'virtualmachine_count': VirtualMachine.objects.filter(platform=instance).count()
  1042. }
  1043. class PlatformEditView(generic.ObjectEditView):
  1044. queryset = Platform.objects.all()
  1045. model_form = forms.PlatformForm
  1046. class PlatformDeleteView(generic.ObjectDeleteView):
  1047. queryset = Platform.objects.all()
  1048. class PlatformBulkImportView(generic.BulkImportView):
  1049. queryset = Platform.objects.all()
  1050. model_form = forms.PlatformCSVForm
  1051. table = tables.PlatformTable
  1052. class PlatformBulkEditView(generic.BulkEditView):
  1053. queryset = Platform.objects.all()
  1054. filterset = filtersets.PlatformFilterSet
  1055. table = tables.PlatformTable
  1056. form = forms.PlatformBulkEditForm
  1057. class PlatformBulkDeleteView(generic.BulkDeleteView):
  1058. queryset = Platform.objects.all()
  1059. table = tables.PlatformTable
  1060. #
  1061. # Devices
  1062. #
  1063. class DeviceListView(generic.ObjectListView):
  1064. queryset = Device.objects.all()
  1065. filterset = filtersets.DeviceFilterSet
  1066. filterset_form = forms.DeviceFilterForm
  1067. table = tables.DeviceTable
  1068. template_name = 'dcim/device_list.html'
  1069. class DeviceView(generic.ObjectView):
  1070. queryset = Device.objects.prefetch_related(
  1071. 'site__region', 'location', 'rack', 'tenant__group', 'device_role', 'platform', 'primary_ip4', 'primary_ip6'
  1072. )
  1073. def get_extra_context(self, request, instance):
  1074. # VirtualChassis members
  1075. if instance.virtual_chassis is not None:
  1076. vc_members = Device.objects.restrict(request.user, 'view').filter(
  1077. virtual_chassis=instance.virtual_chassis
  1078. ).order_by('vc_position')
  1079. else:
  1080. vc_members = []
  1081. # Services
  1082. services = Service.objects.restrict(request.user, 'view').filter(device=instance)
  1083. # Find up to ten devices in the same site with the same functional role for quick reference.
  1084. related_devices = Device.objects.restrict(request.user, 'view').filter(
  1085. site=instance.site, device_role=instance.device_role
  1086. ).exclude(
  1087. pk=instance.pk
  1088. ).prefetch_related(
  1089. 'rack', 'device_type__manufacturer'
  1090. )[:10]
  1091. return {
  1092. 'services': services,
  1093. 'vc_members': vc_members,
  1094. 'related_devices': related_devices,
  1095. 'active_tab': 'device',
  1096. }
  1097. class DeviceConsolePortsView(DeviceComponentsView):
  1098. child_model = ConsolePort
  1099. table = tables.DeviceConsolePortTable
  1100. filterset = filtersets.ConsolePortFilterSet
  1101. template_name = 'dcim/device/consoleports.html'
  1102. class DeviceConsoleServerPortsView(DeviceComponentsView):
  1103. child_model = ConsoleServerPort
  1104. table = tables.DeviceConsoleServerPortTable
  1105. filterset = filtersets.ConsoleServerPortFilterSet
  1106. template_name = 'dcim/device/consoleserverports.html'
  1107. class DevicePowerPortsView(DeviceComponentsView):
  1108. child_model = PowerPort
  1109. table = tables.DevicePowerPortTable
  1110. filterset = filtersets.PowerPortFilterSet
  1111. template_name = 'dcim/device/powerports.html'
  1112. class DevicePowerOutletsView(DeviceComponentsView):
  1113. child_model = PowerOutlet
  1114. table = tables.DevicePowerOutletTable
  1115. filterset = filtersets.PowerOutletFilterSet
  1116. template_name = 'dcim/device/poweroutlets.html'
  1117. class DeviceInterfacesView(DeviceComponentsView):
  1118. child_model = Interface
  1119. table = tables.DeviceInterfaceTable
  1120. filterset = filtersets.InterfaceFilterSet
  1121. template_name = 'dcim/device/interfaces.html'
  1122. def get_children(self, request, parent):
  1123. return parent.vc_interfaces().restrict(request.user, 'view').prefetch_related(
  1124. Prefetch('ip_addresses', queryset=IPAddress.objects.restrict(request.user)),
  1125. Prefetch('member_interfaces', queryset=Interface.objects.restrict(request.user))
  1126. )
  1127. class DeviceFrontPortsView(DeviceComponentsView):
  1128. child_model = FrontPort
  1129. table = tables.DeviceFrontPortTable
  1130. filterset = filtersets.FrontPortFilterSet
  1131. template_name = 'dcim/device/frontports.html'
  1132. class DeviceRearPortsView(DeviceComponentsView):
  1133. child_model = RearPort
  1134. table = tables.DeviceRearPortTable
  1135. filterset = filtersets.RearPortFilterSet
  1136. template_name = 'dcim/device/rearports.html'
  1137. class DeviceModuleBaysView(DeviceComponentsView):
  1138. child_model = ModuleBay
  1139. table = tables.DeviceModuleBayTable
  1140. filterset = filtersets.ModuleBayFilterSet
  1141. template_name = 'dcim/device/modulebays.html'
  1142. class DeviceDeviceBaysView(DeviceComponentsView):
  1143. child_model = DeviceBay
  1144. table = tables.DeviceDeviceBayTable
  1145. filterset = filtersets.DeviceBayFilterSet
  1146. template_name = 'dcim/device/devicebays.html'
  1147. class DeviceInventoryView(DeviceComponentsView):
  1148. child_model = InventoryItem
  1149. table = tables.DeviceInventoryItemTable
  1150. filterset = filtersets.InventoryItemFilterSet
  1151. template_name = 'dcim/device/inventory.html'
  1152. class DeviceStatusView(generic.ObjectView):
  1153. additional_permissions = ['dcim.napalm_read_device']
  1154. queryset = Device.objects.all()
  1155. template_name = 'dcim/device/status.html'
  1156. def get_extra_context(self, request, instance):
  1157. return {
  1158. 'active_tab': 'status',
  1159. }
  1160. class DeviceLLDPNeighborsView(generic.ObjectView):
  1161. additional_permissions = ['dcim.napalm_read_device']
  1162. queryset = Device.objects.all()
  1163. template_name = 'dcim/device/lldp_neighbors.html'
  1164. def get_extra_context(self, request, instance):
  1165. interfaces = instance.vc_interfaces().restrict(request.user, 'view').prefetch_related(
  1166. '_path__destination'
  1167. ).exclude(
  1168. type__in=NONCONNECTABLE_IFACE_TYPES
  1169. )
  1170. return {
  1171. 'interfaces': interfaces,
  1172. 'active_tab': 'lldp-neighbors',
  1173. }
  1174. class DeviceConfigView(generic.ObjectView):
  1175. additional_permissions = ['dcim.napalm_read_device']
  1176. queryset = Device.objects.all()
  1177. template_name = 'dcim/device/config.html'
  1178. def get_extra_context(self, request, instance):
  1179. return {
  1180. 'active_tab': 'config',
  1181. }
  1182. class DeviceConfigContextView(ObjectConfigContextView):
  1183. queryset = Device.objects.annotate_config_context_data()
  1184. base_template = 'dcim/device/base.html'
  1185. class DeviceEditView(generic.ObjectEditView):
  1186. queryset = Device.objects.all()
  1187. model_form = forms.DeviceForm
  1188. template_name = 'dcim/device_edit.html'
  1189. class DeviceDeleteView(generic.ObjectDeleteView):
  1190. queryset = Device.objects.all()
  1191. class DeviceBulkImportView(generic.BulkImportView):
  1192. queryset = Device.objects.all()
  1193. model_form = forms.DeviceCSVForm
  1194. table = tables.DeviceImportTable
  1195. template_name = 'dcim/device_import.html'
  1196. class ChildDeviceBulkImportView(generic.BulkImportView):
  1197. queryset = Device.objects.all()
  1198. model_form = forms.ChildDeviceCSVForm
  1199. table = tables.DeviceImportTable
  1200. template_name = 'dcim/device_import_child.html'
  1201. def _save_obj(self, obj_form, request):
  1202. obj = obj_form.save()
  1203. # Save the reverse relation to the parent device bay
  1204. device_bay = obj.parent_bay
  1205. device_bay.installed_device = obj
  1206. device_bay.save()
  1207. return obj
  1208. class DeviceBulkEditView(generic.BulkEditView):
  1209. queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer')
  1210. filterset = filtersets.DeviceFilterSet
  1211. table = tables.DeviceTable
  1212. form = forms.DeviceBulkEditForm
  1213. class DeviceBulkDeleteView(generic.BulkDeleteView):
  1214. queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer')
  1215. filterset = filtersets.DeviceFilterSet
  1216. table = tables.DeviceTable
  1217. #
  1218. # Devices
  1219. #
  1220. class ModuleListView(generic.ObjectListView):
  1221. queryset = Module.objects.prefetch_related('device', 'module_type__manufacturer')
  1222. filterset = filtersets.ModuleFilterSet
  1223. filterset_form = forms.ModuleFilterForm
  1224. table = tables.ModuleTable
  1225. class ModuleView(generic.ObjectView):
  1226. queryset = Module.objects.all()
  1227. class ModuleEditView(generic.ObjectEditView):
  1228. queryset = Module.objects.all()
  1229. model_form = forms.ModuleForm
  1230. class ModuleDeleteView(generic.ObjectDeleteView):
  1231. queryset = Module.objects.all()
  1232. class ModuleBulkImportView(generic.BulkImportView):
  1233. queryset = Module.objects.all()
  1234. model_form = forms.ModuleCSVForm
  1235. table = tables.ModuleTable
  1236. class ModuleBulkEditView(generic.BulkEditView):
  1237. queryset = Module.objects.prefetch_related('device', 'module_type__manufacturer')
  1238. filterset = filtersets.ModuleFilterSet
  1239. table = tables.ModuleTable
  1240. form = forms.ModuleBulkEditForm
  1241. class ModuleBulkDeleteView(generic.BulkDeleteView):
  1242. queryset = Module.objects.prefetch_related('device', 'module_type__manufacturer')
  1243. filterset = filtersets.ModuleFilterSet
  1244. table = tables.ModuleTable
  1245. #
  1246. # Console ports
  1247. #
  1248. class ConsolePortListView(generic.ObjectListView):
  1249. queryset = ConsolePort.objects.all()
  1250. filterset = filtersets.ConsolePortFilterSet
  1251. filterset_form = forms.ConsolePortFilterForm
  1252. table = tables.ConsolePortTable
  1253. action_buttons = ('import', 'export')
  1254. class ConsolePortView(generic.ObjectView):
  1255. queryset = ConsolePort.objects.all()
  1256. class ConsolePortCreateView(generic.ComponentCreateView):
  1257. queryset = ConsolePort.objects.all()
  1258. form = forms.ConsolePortCreateForm
  1259. model_form = forms.ConsolePortForm
  1260. class ConsolePortEditView(generic.ObjectEditView):
  1261. queryset = ConsolePort.objects.all()
  1262. model_form = forms.ConsolePortForm
  1263. template_name = 'dcim/device_component_edit.html'
  1264. class ConsolePortDeleteView(generic.ObjectDeleteView):
  1265. queryset = ConsolePort.objects.all()
  1266. class ConsolePortBulkImportView(generic.BulkImportView):
  1267. queryset = ConsolePort.objects.all()
  1268. model_form = forms.ConsolePortCSVForm
  1269. table = tables.ConsolePortTable
  1270. class ConsolePortBulkEditView(generic.BulkEditView):
  1271. queryset = ConsolePort.objects.all()
  1272. filterset = filtersets.ConsolePortFilterSet
  1273. table = tables.ConsolePortTable
  1274. form = forms.ConsolePortBulkEditForm
  1275. class ConsolePortBulkRenameView(generic.BulkRenameView):
  1276. queryset = ConsolePort.objects.all()
  1277. class ConsolePortBulkDisconnectView(BulkDisconnectView):
  1278. queryset = ConsolePort.objects.all()
  1279. class ConsolePortBulkDeleteView(generic.BulkDeleteView):
  1280. queryset = ConsolePort.objects.all()
  1281. filterset = filtersets.ConsolePortFilterSet
  1282. table = tables.ConsolePortTable
  1283. #
  1284. # Console server ports
  1285. #
  1286. class ConsoleServerPortListView(generic.ObjectListView):
  1287. queryset = ConsoleServerPort.objects.all()
  1288. filterset = filtersets.ConsoleServerPortFilterSet
  1289. filterset_form = forms.ConsoleServerPortFilterForm
  1290. table = tables.ConsoleServerPortTable
  1291. action_buttons = ('import', 'export')
  1292. class ConsoleServerPortView(generic.ObjectView):
  1293. queryset = ConsoleServerPort.objects.all()
  1294. class ConsoleServerPortCreateView(generic.ComponentCreateView):
  1295. queryset = ConsoleServerPort.objects.all()
  1296. form = forms.ConsoleServerPortCreateForm
  1297. model_form = forms.ConsoleServerPortForm
  1298. class ConsoleServerPortEditView(generic.ObjectEditView):
  1299. queryset = ConsoleServerPort.objects.all()
  1300. model_form = forms.ConsoleServerPortForm
  1301. template_name = 'dcim/device_component_edit.html'
  1302. class ConsoleServerPortDeleteView(generic.ObjectDeleteView):
  1303. queryset = ConsoleServerPort.objects.all()
  1304. class ConsoleServerPortBulkImportView(generic.BulkImportView):
  1305. queryset = ConsoleServerPort.objects.all()
  1306. model_form = forms.ConsoleServerPortCSVForm
  1307. table = tables.ConsoleServerPortTable
  1308. class ConsoleServerPortBulkEditView(generic.BulkEditView):
  1309. queryset = ConsoleServerPort.objects.all()
  1310. filterset = filtersets.ConsoleServerPortFilterSet
  1311. table = tables.ConsoleServerPortTable
  1312. form = forms.ConsoleServerPortBulkEditForm
  1313. class ConsoleServerPortBulkRenameView(generic.BulkRenameView):
  1314. queryset = ConsoleServerPort.objects.all()
  1315. class ConsoleServerPortBulkDisconnectView(BulkDisconnectView):
  1316. queryset = ConsoleServerPort.objects.all()
  1317. class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView):
  1318. queryset = ConsoleServerPort.objects.all()
  1319. filterset = filtersets.ConsoleServerPortFilterSet
  1320. table = tables.ConsoleServerPortTable
  1321. #
  1322. # Power ports
  1323. #
  1324. class PowerPortListView(generic.ObjectListView):
  1325. queryset = PowerPort.objects.all()
  1326. filterset = filtersets.PowerPortFilterSet
  1327. filterset_form = forms.PowerPortFilterForm
  1328. table = tables.PowerPortTable
  1329. action_buttons = ('import', 'export')
  1330. class PowerPortView(generic.ObjectView):
  1331. queryset = PowerPort.objects.all()
  1332. class PowerPortCreateView(generic.ComponentCreateView):
  1333. queryset = PowerPort.objects.all()
  1334. form = forms.PowerPortCreateForm
  1335. model_form = forms.PowerPortForm
  1336. class PowerPortEditView(generic.ObjectEditView):
  1337. queryset = PowerPort.objects.all()
  1338. model_form = forms.PowerPortForm
  1339. template_name = 'dcim/device_component_edit.html'
  1340. class PowerPortDeleteView(generic.ObjectDeleteView):
  1341. queryset = PowerPort.objects.all()
  1342. class PowerPortBulkImportView(generic.BulkImportView):
  1343. queryset = PowerPort.objects.all()
  1344. model_form = forms.PowerPortCSVForm
  1345. table = tables.PowerPortTable
  1346. class PowerPortBulkEditView(generic.BulkEditView):
  1347. queryset = PowerPort.objects.all()
  1348. filterset = filtersets.PowerPortFilterSet
  1349. table = tables.PowerPortTable
  1350. form = forms.PowerPortBulkEditForm
  1351. class PowerPortBulkRenameView(generic.BulkRenameView):
  1352. queryset = PowerPort.objects.all()
  1353. class PowerPortBulkDisconnectView(BulkDisconnectView):
  1354. queryset = PowerPort.objects.all()
  1355. class PowerPortBulkDeleteView(generic.BulkDeleteView):
  1356. queryset = PowerPort.objects.all()
  1357. filterset = filtersets.PowerPortFilterSet
  1358. table = tables.PowerPortTable
  1359. #
  1360. # Power outlets
  1361. #
  1362. class PowerOutletListView(generic.ObjectListView):
  1363. queryset = PowerOutlet.objects.all()
  1364. filterset = filtersets.PowerOutletFilterSet
  1365. filterset_form = forms.PowerOutletFilterForm
  1366. table = tables.PowerOutletTable
  1367. action_buttons = ('import', 'export')
  1368. class PowerOutletView(generic.ObjectView):
  1369. queryset = PowerOutlet.objects.all()
  1370. class PowerOutletCreateView(generic.ComponentCreateView):
  1371. queryset = PowerOutlet.objects.all()
  1372. form = forms.PowerOutletCreateForm
  1373. model_form = forms.PowerOutletForm
  1374. class PowerOutletEditView(generic.ObjectEditView):
  1375. queryset = PowerOutlet.objects.all()
  1376. model_form = forms.PowerOutletForm
  1377. template_name = 'dcim/device_component_edit.html'
  1378. class PowerOutletDeleteView(generic.ObjectDeleteView):
  1379. queryset = PowerOutlet.objects.all()
  1380. class PowerOutletBulkImportView(generic.BulkImportView):
  1381. queryset = PowerOutlet.objects.all()
  1382. model_form = forms.PowerOutletCSVForm
  1383. table = tables.PowerOutletTable
  1384. class PowerOutletBulkEditView(generic.BulkEditView):
  1385. queryset = PowerOutlet.objects.all()
  1386. filterset = filtersets.PowerOutletFilterSet
  1387. table = tables.PowerOutletTable
  1388. form = forms.PowerOutletBulkEditForm
  1389. class PowerOutletBulkRenameView(generic.BulkRenameView):
  1390. queryset = PowerOutlet.objects.all()
  1391. class PowerOutletBulkDisconnectView(BulkDisconnectView):
  1392. queryset = PowerOutlet.objects.all()
  1393. class PowerOutletBulkDeleteView(generic.BulkDeleteView):
  1394. queryset = PowerOutlet.objects.all()
  1395. filterset = filtersets.PowerOutletFilterSet
  1396. table = tables.PowerOutletTable
  1397. #
  1398. # Interfaces
  1399. #
  1400. class InterfaceListView(generic.ObjectListView):
  1401. queryset = Interface.objects.all()
  1402. filterset = filtersets.InterfaceFilterSet
  1403. filterset_form = forms.InterfaceFilterForm
  1404. table = tables.InterfaceTable
  1405. action_buttons = ('import', 'export')
  1406. class InterfaceView(generic.ObjectView):
  1407. queryset = Interface.objects.all()
  1408. def get_extra_context(self, request, instance):
  1409. # Get assigned IP addresses
  1410. ipaddress_table = AssignedIPAddressesTable(
  1411. data=instance.ip_addresses.restrict(request.user, 'view').prefetch_related('vrf', 'tenant'),
  1412. orderable=False
  1413. )
  1414. # Get child interfaces
  1415. child_interfaces = Interface.objects.restrict(request.user, 'view').filter(parent=instance)
  1416. child_interfaces_tables = tables.InterfaceTable(
  1417. child_interfaces,
  1418. exclude=('device', 'parent'),
  1419. orderable=False
  1420. )
  1421. # Get assigned VLANs and annotate whether each is tagged or untagged
  1422. vlans = []
  1423. if instance.untagged_vlan is not None:
  1424. vlans.append(instance.untagged_vlan)
  1425. vlans[0].tagged = False
  1426. for vlan in instance.tagged_vlans.restrict(request.user).prefetch_related('site', 'group', 'tenant', 'role'):
  1427. vlan.tagged = True
  1428. vlans.append(vlan)
  1429. vlan_table = InterfaceVLANTable(
  1430. interface=instance,
  1431. data=vlans,
  1432. orderable=False
  1433. )
  1434. return {
  1435. 'ipaddress_table': ipaddress_table,
  1436. 'child_interfaces_table': child_interfaces_tables,
  1437. 'vlan_table': vlan_table,
  1438. }
  1439. class InterfaceCreateView(generic.ComponentCreateView):
  1440. queryset = Interface.objects.all()
  1441. form = forms.InterfaceCreateForm
  1442. model_form = forms.InterfaceForm
  1443. template_name = 'dcim/interface_create.html'
  1444. def post(self, request):
  1445. """
  1446. Override inherited post() method to handle request to assign newly created
  1447. interface objects (first object) to an IP Address object.
  1448. """
  1449. form = self.form(request.POST, initial=request.GET)
  1450. new_objs = self.validate_form(request, form)
  1451. if form.is_valid() and not form.errors:
  1452. if '_addanother' in request.POST:
  1453. return redirect(request.get_full_path())
  1454. elif new_objs is not None and '_assignip' in request.POST and len(new_objs) >= 1 and \
  1455. request.user.has_perm('ipam.add_ipaddress'):
  1456. first_obj = new_objs[0].pk
  1457. return redirect(
  1458. f'/ipam/ip-addresses/add/?interface={first_obj}&return_url={self.get_return_url(request)}'
  1459. )
  1460. else:
  1461. return redirect(self.get_return_url(request))
  1462. return render(request, self.template_name, {
  1463. 'obj_type': self.queryset.model._meta.verbose_name,
  1464. 'form': form,
  1465. 'return_url': self.get_return_url(request),
  1466. })
  1467. class InterfaceEditView(generic.ObjectEditView):
  1468. queryset = Interface.objects.all()
  1469. model_form = forms.InterfaceForm
  1470. template_name = 'dcim/interface_edit.html'
  1471. class InterfaceDeleteView(generic.ObjectDeleteView):
  1472. queryset = Interface.objects.all()
  1473. class InterfaceBulkImportView(generic.BulkImportView):
  1474. queryset = Interface.objects.all()
  1475. model_form = forms.InterfaceCSVForm
  1476. table = tables.InterfaceTable
  1477. class InterfaceBulkEditView(generic.BulkEditView):
  1478. queryset = Interface.objects.all()
  1479. filterset = filtersets.InterfaceFilterSet
  1480. table = tables.InterfaceTable
  1481. form = forms.InterfaceBulkEditForm
  1482. class InterfaceBulkRenameView(generic.BulkRenameView):
  1483. queryset = Interface.objects.all()
  1484. class InterfaceBulkDisconnectView(BulkDisconnectView):
  1485. queryset = Interface.objects.all()
  1486. class InterfaceBulkDeleteView(generic.BulkDeleteView):
  1487. queryset = Interface.objects.all()
  1488. filterset = filtersets.InterfaceFilterSet
  1489. table = tables.InterfaceTable
  1490. #
  1491. # Front ports
  1492. #
  1493. class FrontPortListView(generic.ObjectListView):
  1494. queryset = FrontPort.objects.all()
  1495. filterset = filtersets.FrontPortFilterSet
  1496. filterset_form = forms.FrontPortFilterForm
  1497. table = tables.FrontPortTable
  1498. action_buttons = ('import', 'export')
  1499. class FrontPortView(generic.ObjectView):
  1500. queryset = FrontPort.objects.all()
  1501. class FrontPortCreateView(generic.ComponentCreateView):
  1502. queryset = FrontPort.objects.all()
  1503. form = forms.FrontPortCreateForm
  1504. model_form = forms.FrontPortForm
  1505. class FrontPortEditView(generic.ObjectEditView):
  1506. queryset = FrontPort.objects.all()
  1507. model_form = forms.FrontPortForm
  1508. template_name = 'dcim/device_component_edit.html'
  1509. class FrontPortDeleteView(generic.ObjectDeleteView):
  1510. queryset = FrontPort.objects.all()
  1511. class FrontPortBulkImportView(generic.BulkImportView):
  1512. queryset = FrontPort.objects.all()
  1513. model_form = forms.FrontPortCSVForm
  1514. table = tables.FrontPortTable
  1515. class FrontPortBulkEditView(generic.BulkEditView):
  1516. queryset = FrontPort.objects.all()
  1517. filterset = filtersets.FrontPortFilterSet
  1518. table = tables.FrontPortTable
  1519. form = forms.FrontPortBulkEditForm
  1520. class FrontPortBulkRenameView(generic.BulkRenameView):
  1521. queryset = FrontPort.objects.all()
  1522. class FrontPortBulkDisconnectView(BulkDisconnectView):
  1523. queryset = FrontPort.objects.all()
  1524. class FrontPortBulkDeleteView(generic.BulkDeleteView):
  1525. queryset = FrontPort.objects.all()
  1526. filterset = filtersets.FrontPortFilterSet
  1527. table = tables.FrontPortTable
  1528. #
  1529. # Rear ports
  1530. #
  1531. class RearPortListView(generic.ObjectListView):
  1532. queryset = RearPort.objects.all()
  1533. filterset = filtersets.RearPortFilterSet
  1534. filterset_form = forms.RearPortFilterForm
  1535. table = tables.RearPortTable
  1536. action_buttons = ('import', 'export')
  1537. class RearPortView(generic.ObjectView):
  1538. queryset = RearPort.objects.all()
  1539. class RearPortCreateView(generic.ComponentCreateView):
  1540. queryset = RearPort.objects.all()
  1541. form = forms.RearPortCreateForm
  1542. model_form = forms.RearPortForm
  1543. class RearPortEditView(generic.ObjectEditView):
  1544. queryset = RearPort.objects.all()
  1545. model_form = forms.RearPortForm
  1546. template_name = 'dcim/device_component_edit.html'
  1547. class RearPortDeleteView(generic.ObjectDeleteView):
  1548. queryset = RearPort.objects.all()
  1549. class RearPortBulkImportView(generic.BulkImportView):
  1550. queryset = RearPort.objects.all()
  1551. model_form = forms.RearPortCSVForm
  1552. table = tables.RearPortTable
  1553. class RearPortBulkEditView(generic.BulkEditView):
  1554. queryset = RearPort.objects.all()
  1555. filterset = filtersets.RearPortFilterSet
  1556. table = tables.RearPortTable
  1557. form = forms.RearPortBulkEditForm
  1558. class RearPortBulkRenameView(generic.BulkRenameView):
  1559. queryset = RearPort.objects.all()
  1560. class RearPortBulkDisconnectView(BulkDisconnectView):
  1561. queryset = RearPort.objects.all()
  1562. class RearPortBulkDeleteView(generic.BulkDeleteView):
  1563. queryset = RearPort.objects.all()
  1564. filterset = filtersets.RearPortFilterSet
  1565. table = tables.RearPortTable
  1566. #
  1567. # Module bays
  1568. #
  1569. class ModuleBayListView(generic.ObjectListView):
  1570. queryset = ModuleBay.objects.select_related('installed_module__module_type')
  1571. filterset = filtersets.ModuleBayFilterSet
  1572. filterset_form = forms.ModuleBayFilterForm
  1573. table = tables.ModuleBayTable
  1574. action_buttons = ('import', 'export')
  1575. class ModuleBayView(generic.ObjectView):
  1576. queryset = ModuleBay.objects.all()
  1577. class ModuleBayCreateView(generic.ComponentCreateView):
  1578. queryset = ModuleBay.objects.all()
  1579. form = forms.ModuleBayCreateForm
  1580. model_form = forms.ModuleBayForm
  1581. class ModuleBayEditView(generic.ObjectEditView):
  1582. queryset = ModuleBay.objects.all()
  1583. model_form = forms.ModuleBayForm
  1584. template_name = 'dcim/device_component_edit.html'
  1585. class ModuleBayDeleteView(generic.ObjectDeleteView):
  1586. queryset = ModuleBay.objects.all()
  1587. class ModuleBayBulkImportView(generic.BulkImportView):
  1588. queryset = ModuleBay.objects.all()
  1589. model_form = forms.ModuleBayCSVForm
  1590. table = tables.ModuleBayTable
  1591. class ModuleBayBulkEditView(generic.BulkEditView):
  1592. queryset = ModuleBay.objects.all()
  1593. filterset = filtersets.ModuleBayFilterSet
  1594. table = tables.ModuleBayTable
  1595. form = forms.ModuleBayBulkEditForm
  1596. class ModuleBayBulkRenameView(generic.BulkRenameView):
  1597. queryset = ModuleBay.objects.all()
  1598. class ModuleBayBulkDeleteView(generic.BulkDeleteView):
  1599. queryset = ModuleBay.objects.all()
  1600. filterset = filtersets.ModuleBayFilterSet
  1601. table = tables.ModuleBayTable
  1602. #
  1603. # Device bays
  1604. #
  1605. class DeviceBayListView(generic.ObjectListView):
  1606. queryset = DeviceBay.objects.all()
  1607. filterset = filtersets.DeviceBayFilterSet
  1608. filterset_form = forms.DeviceBayFilterForm
  1609. table = tables.DeviceBayTable
  1610. action_buttons = ('import', 'export')
  1611. class DeviceBayView(generic.ObjectView):
  1612. queryset = DeviceBay.objects.all()
  1613. class DeviceBayCreateView(generic.ComponentCreateView):
  1614. queryset = DeviceBay.objects.all()
  1615. form = forms.DeviceBayCreateForm
  1616. model_form = forms.DeviceBayForm
  1617. class DeviceBayEditView(generic.ObjectEditView):
  1618. queryset = DeviceBay.objects.all()
  1619. model_form = forms.DeviceBayForm
  1620. template_name = 'dcim/device_component_edit.html'
  1621. class DeviceBayDeleteView(generic.ObjectDeleteView):
  1622. queryset = DeviceBay.objects.all()
  1623. class DeviceBayPopulateView(generic.ObjectEditView):
  1624. queryset = DeviceBay.objects.all()
  1625. def get(self, request, pk):
  1626. device_bay = get_object_or_404(self.queryset, pk=pk)
  1627. form = forms.PopulateDeviceBayForm(device_bay)
  1628. return render(request, 'dcim/devicebay_populate.html', {
  1629. 'device_bay': device_bay,
  1630. 'form': form,
  1631. 'return_url': self.get_return_url(request, device_bay),
  1632. })
  1633. def post(self, request, pk):
  1634. device_bay = get_object_or_404(self.queryset, pk=pk)
  1635. form = forms.PopulateDeviceBayForm(device_bay, request.POST)
  1636. if form.is_valid():
  1637. device_bay.installed_device = form.cleaned_data['installed_device']
  1638. device_bay.save()
  1639. messages.success(request, "Added {} to {}.".format(device_bay.installed_device, device_bay))
  1640. return redirect('dcim:device', pk=device_bay.device.pk)
  1641. return render(request, 'dcim/devicebay_populate.html', {
  1642. 'device_bay': device_bay,
  1643. 'form': form,
  1644. 'return_url': self.get_return_url(request, device_bay),
  1645. })
  1646. class DeviceBayDepopulateView(generic.ObjectEditView):
  1647. queryset = DeviceBay.objects.all()
  1648. def get(self, request, pk):
  1649. device_bay = get_object_or_404(self.queryset, pk=pk)
  1650. form = ConfirmationForm()
  1651. return render(request, 'dcim/devicebay_depopulate.html', {
  1652. 'device_bay': device_bay,
  1653. 'form': form,
  1654. 'return_url': self.get_return_url(request, device_bay),
  1655. })
  1656. def post(self, request, pk):
  1657. device_bay = get_object_or_404(self.queryset, pk=pk)
  1658. form = ConfirmationForm(request.POST)
  1659. if form.is_valid():
  1660. removed_device = device_bay.installed_device
  1661. device_bay.installed_device = None
  1662. device_bay.save()
  1663. messages.success(request, f"{removed_device} has been removed from {device_bay}.")
  1664. return_url = self.get_return_url(request, device_bay.device)
  1665. return redirect(return_url)
  1666. return render(request, 'dcim/devicebay_depopulate.html', {
  1667. 'device_bay': device_bay,
  1668. 'form': form,
  1669. 'return_url': self.get_return_url(request, device_bay),
  1670. })
  1671. class DeviceBayBulkImportView(generic.BulkImportView):
  1672. queryset = DeviceBay.objects.all()
  1673. model_form = forms.DeviceBayCSVForm
  1674. table = tables.DeviceBayTable
  1675. class DeviceBayBulkEditView(generic.BulkEditView):
  1676. queryset = DeviceBay.objects.all()
  1677. filterset = filtersets.DeviceBayFilterSet
  1678. table = tables.DeviceBayTable
  1679. form = forms.DeviceBayBulkEditForm
  1680. class DeviceBayBulkRenameView(generic.BulkRenameView):
  1681. queryset = DeviceBay.objects.all()
  1682. class DeviceBayBulkDeleteView(generic.BulkDeleteView):
  1683. queryset = DeviceBay.objects.all()
  1684. filterset = filtersets.DeviceBayFilterSet
  1685. table = tables.DeviceBayTable
  1686. #
  1687. # Inventory items
  1688. #
  1689. class InventoryItemListView(generic.ObjectListView):
  1690. queryset = InventoryItem.objects.all()
  1691. filterset = filtersets.InventoryItemFilterSet
  1692. filterset_form = forms.InventoryItemFilterForm
  1693. table = tables.InventoryItemTable
  1694. action_buttons = ('import', 'export')
  1695. class InventoryItemView(generic.ObjectView):
  1696. queryset = InventoryItem.objects.all()
  1697. class InventoryItemEditView(generic.ObjectEditView):
  1698. queryset = InventoryItem.objects.all()
  1699. model_form = forms.InventoryItemForm
  1700. class InventoryItemCreateView(generic.ComponentCreateView):
  1701. queryset = InventoryItem.objects.all()
  1702. form = forms.InventoryItemCreateForm
  1703. model_form = forms.InventoryItemForm
  1704. class InventoryItemDeleteView(generic.ObjectDeleteView):
  1705. queryset = InventoryItem.objects.all()
  1706. class InventoryItemBulkImportView(generic.BulkImportView):
  1707. queryset = InventoryItem.objects.all()
  1708. model_form = forms.InventoryItemCSVForm
  1709. table = tables.InventoryItemTable
  1710. class InventoryItemBulkEditView(generic.BulkEditView):
  1711. queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer')
  1712. filterset = filtersets.InventoryItemFilterSet
  1713. table = tables.InventoryItemTable
  1714. form = forms.InventoryItemBulkEditForm
  1715. class InventoryItemBulkRenameView(generic.BulkRenameView):
  1716. queryset = InventoryItem.objects.all()
  1717. class InventoryItemBulkDeleteView(generic.BulkDeleteView):
  1718. queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer')
  1719. table = tables.InventoryItemTable
  1720. template_name = 'dcim/inventoryitem_bulk_delete.html'
  1721. #
  1722. # Bulk Device component creation
  1723. #
  1724. class DeviceBulkAddConsolePortView(generic.BulkComponentCreateView):
  1725. parent_model = Device
  1726. parent_field = 'device'
  1727. form = forms.ConsolePortBulkCreateForm
  1728. queryset = ConsolePort.objects.all()
  1729. model_form = forms.ConsolePortForm
  1730. filterset = filtersets.DeviceFilterSet
  1731. table = tables.DeviceTable
  1732. default_return_url = 'dcim:device_list'
  1733. class DeviceBulkAddConsoleServerPortView(generic.BulkComponentCreateView):
  1734. parent_model = Device
  1735. parent_field = 'device'
  1736. form = forms.ConsoleServerPortBulkCreateForm
  1737. queryset = ConsoleServerPort.objects.all()
  1738. model_form = forms.ConsoleServerPortForm
  1739. filterset = filtersets.DeviceFilterSet
  1740. table = tables.DeviceTable
  1741. default_return_url = 'dcim:device_list'
  1742. class DeviceBulkAddPowerPortView(generic.BulkComponentCreateView):
  1743. parent_model = Device
  1744. parent_field = 'device'
  1745. form = forms.PowerPortBulkCreateForm
  1746. queryset = PowerPort.objects.all()
  1747. model_form = forms.PowerPortForm
  1748. filterset = filtersets.DeviceFilterSet
  1749. table = tables.DeviceTable
  1750. default_return_url = 'dcim:device_list'
  1751. class DeviceBulkAddPowerOutletView(generic.BulkComponentCreateView):
  1752. parent_model = Device
  1753. parent_field = 'device'
  1754. form = forms.PowerOutletBulkCreateForm
  1755. queryset = PowerOutlet.objects.all()
  1756. model_form = forms.PowerOutletForm
  1757. filterset = filtersets.DeviceFilterSet
  1758. table = tables.DeviceTable
  1759. default_return_url = 'dcim:device_list'
  1760. class DeviceBulkAddInterfaceView(generic.BulkComponentCreateView):
  1761. parent_model = Device
  1762. parent_field = 'device'
  1763. form = forms.InterfaceBulkCreateForm
  1764. queryset = Interface.objects.all()
  1765. model_form = forms.InterfaceForm
  1766. filterset = filtersets.DeviceFilterSet
  1767. table = tables.DeviceTable
  1768. default_return_url = 'dcim:device_list'
  1769. # class DeviceBulkAddFrontPortView(generic.BulkComponentCreateView):
  1770. # parent_model = Device
  1771. # parent_field = 'device'
  1772. # form = forms.FrontPortBulkCreateForm
  1773. # queryset = FrontPort.objects.all()
  1774. # model_form = forms.FrontPortForm
  1775. # filterset = filtersets.DeviceFilterSet
  1776. # table = tables.DeviceTable
  1777. # default_return_url = 'dcim:device_list'
  1778. class DeviceBulkAddRearPortView(generic.BulkComponentCreateView):
  1779. parent_model = Device
  1780. parent_field = 'device'
  1781. form = forms.RearPortBulkCreateForm
  1782. queryset = RearPort.objects.all()
  1783. model_form = forms.RearPortForm
  1784. filterset = filtersets.DeviceFilterSet
  1785. table = tables.DeviceTable
  1786. default_return_url = 'dcim:device_list'
  1787. class DeviceBulkAddModuleBayView(generic.BulkComponentCreateView):
  1788. parent_model = Device
  1789. parent_field = 'device'
  1790. form = forms.ModuleBayBulkCreateForm
  1791. queryset = ModuleBay.objects.all()
  1792. model_form = forms.ModuleBayForm
  1793. filterset = filtersets.DeviceFilterSet
  1794. table = tables.DeviceTable
  1795. default_return_url = 'dcim:device_list'
  1796. class DeviceBulkAddDeviceBayView(generic.BulkComponentCreateView):
  1797. parent_model = Device
  1798. parent_field = 'device'
  1799. form = forms.DeviceBayBulkCreateForm
  1800. queryset = DeviceBay.objects.all()
  1801. model_form = forms.DeviceBayForm
  1802. filterset = filtersets.DeviceFilterSet
  1803. table = tables.DeviceTable
  1804. default_return_url = 'dcim:device_list'
  1805. class DeviceBulkAddInventoryItemView(generic.BulkComponentCreateView):
  1806. parent_model = Device
  1807. parent_field = 'device'
  1808. form = forms.InventoryItemBulkCreateForm
  1809. queryset = InventoryItem.objects.all()
  1810. model_form = forms.InventoryItemForm
  1811. filterset = filtersets.DeviceFilterSet
  1812. table = tables.DeviceTable
  1813. default_return_url = 'dcim:device_list'
  1814. #
  1815. # Cables
  1816. #
  1817. class CableListView(generic.ObjectListView):
  1818. queryset = Cable.objects.all()
  1819. filterset = filtersets.CableFilterSet
  1820. filterset_form = forms.CableFilterForm
  1821. table = tables.CableTable
  1822. action_buttons = ('import', 'export')
  1823. class CableView(generic.ObjectView):
  1824. queryset = Cable.objects.all()
  1825. class PathTraceView(generic.ObjectView):
  1826. """
  1827. Trace a cable path beginning from the given path endpoint (origin).
  1828. """
  1829. additional_permissions = ['dcim.view_cable']
  1830. template_name = 'dcim/cable_trace.html'
  1831. def dispatch(self, request, *args, **kwargs):
  1832. model = kwargs.pop('model')
  1833. self.queryset = model.objects.all()
  1834. return super().dispatch(request, *args, **kwargs)
  1835. def get_extra_context(self, request, instance):
  1836. related_paths = []
  1837. # If tracing a PathEndpoint, locate the CablePath (if one exists) by its origin
  1838. if isinstance(instance, PathEndpoint):
  1839. path = instance._path
  1840. # Otherwise, find all CablePaths which traverse the specified object
  1841. else:
  1842. related_paths = CablePath.objects.filter(path__contains=instance).prefetch_related('origin')
  1843. # Check for specification of a particular path (when tracing pass-through ports)
  1844. try:
  1845. path_id = int(request.GET.get('cablepath_id'))
  1846. except TypeError:
  1847. path_id = None
  1848. if path_id in list(related_paths.values_list('pk', flat=True)):
  1849. path = CablePath.objects.get(pk=path_id)
  1850. else:
  1851. path = related_paths.first()
  1852. # No paths found
  1853. if path is None:
  1854. return {
  1855. 'path': None
  1856. }
  1857. # Get the total length of the cable and whether the length is definitive (fully defined)
  1858. total_length, is_definitive = path.get_total_length() if path else (None, False)
  1859. # Determine the path to the SVG trace image
  1860. api_viewname = f"{path.origin._meta.app_label}-api:{path.origin._meta.model_name}-trace"
  1861. svg_url = f"{reverse(api_viewname, kwargs={'pk': path.origin.pk})}?render=svg"
  1862. return {
  1863. 'path': path,
  1864. 'related_paths': related_paths,
  1865. 'total_length': total_length,
  1866. 'is_definitive': is_definitive,
  1867. 'svg_url': svg_url,
  1868. }
  1869. class CableCreateView(generic.ObjectEditView):
  1870. queryset = Cable.objects.all()
  1871. template_name = 'dcim/cable_connect.html'
  1872. def dispatch(self, request, *args, **kwargs):
  1873. # Set the model_form class based on the type of component being connected
  1874. self.model_form = {
  1875. 'console-port': forms.ConnectCableToConsolePortForm,
  1876. 'console-server-port': forms.ConnectCableToConsoleServerPortForm,
  1877. 'power-port': forms.ConnectCableToPowerPortForm,
  1878. 'power-outlet': forms.ConnectCableToPowerOutletForm,
  1879. 'interface': forms.ConnectCableToInterfaceForm,
  1880. 'front-port': forms.ConnectCableToFrontPortForm,
  1881. 'rear-port': forms.ConnectCableToRearPortForm,
  1882. 'power-feed': forms.ConnectCableToPowerFeedForm,
  1883. 'circuit-termination': forms.ConnectCableToCircuitTerminationForm,
  1884. }[kwargs.get('termination_b_type')]
  1885. return super().dispatch(request, *args, **kwargs)
  1886. def alter_object(self, obj, request, url_args, url_kwargs):
  1887. termination_a_type = url_kwargs.get('termination_a_type')
  1888. termination_a_id = url_kwargs.get('termination_a_id')
  1889. termination_b_type_name = url_kwargs.get('termination_b_type')
  1890. self.termination_b_type = ContentType.objects.get(model=termination_b_type_name.replace('-', ''))
  1891. # Initialize Cable termination attributes
  1892. obj.termination_a = termination_a_type.objects.get(pk=termination_a_id)
  1893. obj.termination_b_type = self.termination_b_type
  1894. return obj
  1895. def get(self, request, *args, **kwargs):
  1896. obj = self.get_object(**kwargs)
  1897. obj = self.alter_object(obj, request, args, kwargs)
  1898. # Parse initial data manually to avoid setting field values as lists
  1899. initial_data = {k: request.GET[k] for k in request.GET}
  1900. # Set initial site and rack based on side A termination (if not already set)
  1901. termination_a_site = getattr(obj.termination_a.parent_object, 'site', None)
  1902. if termination_a_site and 'termination_b_region' not in initial_data:
  1903. initial_data['termination_b_region'] = termination_a_site.region
  1904. if termination_a_site and 'termination_b_site_group' not in initial_data:
  1905. initial_data['termination_b_site_group'] = termination_a_site.group
  1906. if 'termination_b_site' not in initial_data:
  1907. initial_data['termination_b_site'] = termination_a_site
  1908. if 'termination_b_rack' not in initial_data:
  1909. initial_data['termination_b_rack'] = getattr(obj.termination_a.parent_object, 'rack', None)
  1910. form = self.model_form(instance=obj, initial=initial_data)
  1911. return render(request, self.template_name, {
  1912. 'obj': obj,
  1913. 'obj_type': Cable._meta.verbose_name,
  1914. 'termination_b_type': self.termination_b_type.name,
  1915. 'form': form,
  1916. 'return_url': self.get_return_url(request, obj),
  1917. })
  1918. class CableEditView(generic.ObjectEditView):
  1919. queryset = Cable.objects.all()
  1920. model_form = forms.CableForm
  1921. template_name = 'dcim/cable_edit.html'
  1922. class CableDeleteView(generic.ObjectDeleteView):
  1923. queryset = Cable.objects.all()
  1924. class CableBulkImportView(generic.BulkImportView):
  1925. queryset = Cable.objects.all()
  1926. model_form = forms.CableCSVForm
  1927. table = tables.CableTable
  1928. class CableBulkEditView(generic.BulkEditView):
  1929. queryset = Cable.objects.prefetch_related('termination_a', 'termination_b')
  1930. filterset = filtersets.CableFilterSet
  1931. table = tables.CableTable
  1932. form = forms.CableBulkEditForm
  1933. class CableBulkDeleteView(generic.BulkDeleteView):
  1934. queryset = Cable.objects.prefetch_related('termination_a', 'termination_b')
  1935. filterset = filtersets.CableFilterSet
  1936. table = tables.CableTable
  1937. #
  1938. # Connections
  1939. #
  1940. class ConsoleConnectionsListView(generic.ObjectListView):
  1941. queryset = ConsolePort.objects.filter(_path__isnull=False).order_by('device')
  1942. filterset = filtersets.ConsoleConnectionFilterSet
  1943. filterset_form = forms.ConsoleConnectionFilterForm
  1944. table = tables.ConsoleConnectionTable
  1945. template_name = 'dcim/connections_list.html'
  1946. action_buttons = ('export',)
  1947. def get_extra_context(self, request):
  1948. return {
  1949. 'title': 'Console Connections'
  1950. }
  1951. class PowerConnectionsListView(generic.ObjectListView):
  1952. queryset = PowerPort.objects.filter(_path__isnull=False).order_by('device')
  1953. filterset = filtersets.PowerConnectionFilterSet
  1954. filterset_form = forms.PowerConnectionFilterForm
  1955. table = tables.PowerConnectionTable
  1956. template_name = 'dcim/connections_list.html'
  1957. action_buttons = ('export',)
  1958. def get_extra_context(self, request):
  1959. return {
  1960. 'title': 'Power Connections'
  1961. }
  1962. class InterfaceConnectionsListView(generic.ObjectListView):
  1963. queryset = Interface.objects.filter(_path__isnull=False).order_by('device')
  1964. filterset = filtersets.InterfaceConnectionFilterSet
  1965. filterset_form = forms.InterfaceConnectionFilterForm
  1966. table = tables.InterfaceConnectionTable
  1967. template_name = 'dcim/connections_list.html'
  1968. action_buttons = ('export',)
  1969. def get_extra_context(self, request):
  1970. return {
  1971. 'title': 'Interface Connections'
  1972. }
  1973. #
  1974. # Virtual chassis
  1975. #
  1976. class VirtualChassisListView(generic.ObjectListView):
  1977. queryset = VirtualChassis.objects.prefetch_related('master').annotate(
  1978. member_count=count_related(Device, 'virtual_chassis')
  1979. )
  1980. table = tables.VirtualChassisTable
  1981. filterset = filtersets.VirtualChassisFilterSet
  1982. filterset_form = forms.VirtualChassisFilterForm
  1983. class VirtualChassisView(generic.ObjectView):
  1984. queryset = VirtualChassis.objects.all()
  1985. def get_extra_context(self, request, instance):
  1986. members = Device.objects.restrict(request.user).filter(virtual_chassis=instance)
  1987. return {
  1988. 'members': members,
  1989. }
  1990. class VirtualChassisCreateView(generic.ObjectEditView):
  1991. queryset = VirtualChassis.objects.all()
  1992. model_form = forms.VirtualChassisCreateForm
  1993. template_name = 'dcim/virtualchassis_add.html'
  1994. class VirtualChassisEditView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  1995. queryset = VirtualChassis.objects.all()
  1996. def get_required_permission(self):
  1997. return 'dcim.change_virtualchassis'
  1998. def get(self, request, pk):
  1999. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  2000. VCMemberFormSet = modelformset_factory(
  2001. model=Device,
  2002. form=forms.DeviceVCMembershipForm,
  2003. formset=forms.BaseVCMemberFormSet,
  2004. extra=0
  2005. )
  2006. members_queryset = virtual_chassis.members.prefetch_related('rack').order_by('vc_position')
  2007. vc_form = forms.VirtualChassisForm(instance=virtual_chassis)
  2008. vc_form.fields['master'].queryset = members_queryset
  2009. formset = VCMemberFormSet(queryset=members_queryset)
  2010. return render(request, 'dcim/virtualchassis_edit.html', {
  2011. 'vc_form': vc_form,
  2012. 'formset': formset,
  2013. 'return_url': self.get_return_url(request, virtual_chassis),
  2014. })
  2015. def post(self, request, pk):
  2016. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  2017. VCMemberFormSet = modelformset_factory(
  2018. model=Device,
  2019. form=forms.DeviceVCMembershipForm,
  2020. formset=forms.BaseVCMemberFormSet,
  2021. extra=0
  2022. )
  2023. members_queryset = virtual_chassis.members.prefetch_related('rack').order_by('vc_position')
  2024. vc_form = forms.VirtualChassisForm(request.POST, instance=virtual_chassis)
  2025. vc_form.fields['master'].queryset = members_queryset
  2026. formset = VCMemberFormSet(request.POST, queryset=members_queryset)
  2027. if vc_form.is_valid() and formset.is_valid():
  2028. with transaction.atomic():
  2029. # Save the VirtualChassis
  2030. vc_form.save()
  2031. # Nullify the vc_position of each member first to allow reordering without raising an IntegrityError on
  2032. # duplicate positions. Then save each member instance.
  2033. members = formset.save(commit=False)
  2034. devices = Device.objects.filter(pk__in=[m.pk for m in members])
  2035. for device in devices:
  2036. device.vc_position = None
  2037. device.save()
  2038. for member in members:
  2039. member.save()
  2040. return redirect(virtual_chassis.get_absolute_url())
  2041. return render(request, 'dcim/virtualchassis_edit.html', {
  2042. 'vc_form': vc_form,
  2043. 'formset': formset,
  2044. 'return_url': self.get_return_url(request, virtual_chassis),
  2045. })
  2046. class VirtualChassisDeleteView(generic.ObjectDeleteView):
  2047. queryset = VirtualChassis.objects.all()
  2048. class VirtualChassisAddMemberView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  2049. queryset = VirtualChassis.objects.all()
  2050. def get_required_permission(self):
  2051. return 'dcim.change_virtualchassis'
  2052. def get(self, request, pk):
  2053. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  2054. initial_data = {k: request.GET[k] for k in request.GET}
  2055. member_select_form = forms.VCMemberSelectForm(initial=initial_data)
  2056. membership_form = forms.DeviceVCMembershipForm(initial=initial_data)
  2057. return render(request, 'dcim/virtualchassis_add_member.html', {
  2058. 'virtual_chassis': virtual_chassis,
  2059. 'member_select_form': member_select_form,
  2060. 'membership_form': membership_form,
  2061. 'return_url': self.get_return_url(request, virtual_chassis),
  2062. })
  2063. def post(self, request, pk):
  2064. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  2065. member_select_form = forms.VCMemberSelectForm(request.POST)
  2066. if member_select_form.is_valid():
  2067. device = member_select_form.cleaned_data['device']
  2068. device.virtual_chassis = virtual_chassis
  2069. data = {k: request.POST[k] for k in ['vc_position', 'vc_priority']}
  2070. membership_form = forms.DeviceVCMembershipForm(data=data, validate_vc_position=True, instance=device)
  2071. if membership_form.is_valid():
  2072. membership_form.save()
  2073. msg = 'Added member <a href="{}">{}</a>'.format(device.get_absolute_url(), escape(device))
  2074. messages.success(request, mark_safe(msg))
  2075. if '_addanother' in request.POST:
  2076. return redirect(request.get_full_path())
  2077. return redirect(self.get_return_url(request, device))
  2078. else:
  2079. membership_form = forms.DeviceVCMembershipForm(data=request.POST)
  2080. return render(request, 'dcim/virtualchassis_add_member.html', {
  2081. 'virtual_chassis': virtual_chassis,
  2082. 'member_select_form': member_select_form,
  2083. 'membership_form': membership_form,
  2084. 'return_url': self.get_return_url(request, virtual_chassis),
  2085. })
  2086. class VirtualChassisRemoveMemberView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  2087. queryset = Device.objects.all()
  2088. def get_required_permission(self):
  2089. return 'dcim.change_device'
  2090. def get(self, request, pk):
  2091. device = get_object_or_404(self.queryset, pk=pk, virtual_chassis__isnull=False)
  2092. form = ConfirmationForm(initial=request.GET)
  2093. return render(request, 'dcim/virtualchassis_remove_member.html', {
  2094. 'device': device,
  2095. 'form': form,
  2096. 'return_url': self.get_return_url(request, device),
  2097. })
  2098. def post(self, request, pk):
  2099. device = get_object_or_404(self.queryset, pk=pk, virtual_chassis__isnull=False)
  2100. form = ConfirmationForm(request.POST)
  2101. # Protect master device from being removed
  2102. virtual_chassis = VirtualChassis.objects.filter(master=device).first()
  2103. if virtual_chassis is not None:
  2104. msg = 'Unable to remove master device {} from the virtual chassis.'.format(escape(device))
  2105. messages.error(request, mark_safe(msg))
  2106. return redirect(device.get_absolute_url())
  2107. if form.is_valid():
  2108. devices = Device.objects.filter(pk=device.pk)
  2109. for device in devices:
  2110. device.virtual_chassis = None
  2111. device.vc_position = None
  2112. device.vc_priority = None
  2113. device.save()
  2114. msg = 'Removed {} from virtual chassis {}'.format(device, device.virtual_chassis)
  2115. messages.success(request, msg)
  2116. return redirect(self.get_return_url(request, device))
  2117. return render(request, 'dcim/virtualchassis_remove_member.html', {
  2118. 'device': device,
  2119. 'form': form,
  2120. 'return_url': self.get_return_url(request, device),
  2121. })
  2122. class VirtualChassisBulkImportView(generic.BulkImportView):
  2123. queryset = VirtualChassis.objects.all()
  2124. model_form = forms.VirtualChassisCSVForm
  2125. table = tables.VirtualChassisTable
  2126. class VirtualChassisBulkEditView(generic.BulkEditView):
  2127. queryset = VirtualChassis.objects.all()
  2128. filterset = filtersets.VirtualChassisFilterSet
  2129. table = tables.VirtualChassisTable
  2130. form = forms.VirtualChassisBulkEditForm
  2131. class VirtualChassisBulkDeleteView(generic.BulkDeleteView):
  2132. queryset = VirtualChassis.objects.all()
  2133. filterset = filtersets.VirtualChassisFilterSet
  2134. table = tables.VirtualChassisTable
  2135. #
  2136. # Power panels
  2137. #
  2138. class PowerPanelListView(generic.ObjectListView):
  2139. queryset = PowerPanel.objects.prefetch_related(
  2140. 'site', 'location'
  2141. ).annotate(
  2142. powerfeed_count=count_related(PowerFeed, 'power_panel')
  2143. )
  2144. filterset = filtersets.PowerPanelFilterSet
  2145. filterset_form = forms.PowerPanelFilterForm
  2146. table = tables.PowerPanelTable
  2147. class PowerPanelView(generic.ObjectView):
  2148. queryset = PowerPanel.objects.prefetch_related('site', 'location')
  2149. def get_extra_context(self, request, instance):
  2150. power_feeds = PowerFeed.objects.restrict(request.user).filter(power_panel=instance).prefetch_related('rack')
  2151. powerfeed_table = tables.PowerFeedTable(
  2152. data=power_feeds,
  2153. orderable=False
  2154. )
  2155. if request.user.has_perm('dcim.delete_cable'):
  2156. powerfeed_table.columns.show('pk')
  2157. powerfeed_table.exclude = ['power_panel']
  2158. return {
  2159. 'powerfeed_table': powerfeed_table,
  2160. }
  2161. class PowerPanelEditView(generic.ObjectEditView):
  2162. queryset = PowerPanel.objects.all()
  2163. model_form = forms.PowerPanelForm
  2164. class PowerPanelDeleteView(generic.ObjectDeleteView):
  2165. queryset = PowerPanel.objects.all()
  2166. class PowerPanelBulkImportView(generic.BulkImportView):
  2167. queryset = PowerPanel.objects.all()
  2168. model_form = forms.PowerPanelCSVForm
  2169. table = tables.PowerPanelTable
  2170. class PowerPanelBulkEditView(generic.BulkEditView):
  2171. queryset = PowerPanel.objects.prefetch_related('site', 'location')
  2172. filterset = filtersets.PowerPanelFilterSet
  2173. table = tables.PowerPanelTable
  2174. form = forms.PowerPanelBulkEditForm
  2175. class PowerPanelBulkDeleteView(generic.BulkDeleteView):
  2176. queryset = PowerPanel.objects.prefetch_related(
  2177. 'site', 'location'
  2178. ).annotate(
  2179. powerfeed_count=count_related(PowerFeed, 'power_panel')
  2180. )
  2181. filterset = filtersets.PowerPanelFilterSet
  2182. table = tables.PowerPanelTable
  2183. #
  2184. # Power feeds
  2185. #
  2186. class PowerFeedListView(generic.ObjectListView):
  2187. queryset = PowerFeed.objects.all()
  2188. filterset = filtersets.PowerFeedFilterSet
  2189. filterset_form = forms.PowerFeedFilterForm
  2190. table = tables.PowerFeedTable
  2191. class PowerFeedView(generic.ObjectView):
  2192. queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack')
  2193. class PowerFeedEditView(generic.ObjectEditView):
  2194. queryset = PowerFeed.objects.all()
  2195. model_form = forms.PowerFeedForm
  2196. class PowerFeedDeleteView(generic.ObjectDeleteView):
  2197. queryset = PowerFeed.objects.all()
  2198. class PowerFeedBulkImportView(generic.BulkImportView):
  2199. queryset = PowerFeed.objects.all()
  2200. model_form = forms.PowerFeedCSVForm
  2201. table = tables.PowerFeedTable
  2202. class PowerFeedBulkEditView(generic.BulkEditView):
  2203. queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack')
  2204. filterset = filtersets.PowerFeedFilterSet
  2205. table = tables.PowerFeedTable
  2206. form = forms.PowerFeedBulkEditForm
  2207. class PowerFeedBulkDisconnectView(BulkDisconnectView):
  2208. queryset = PowerFeed.objects.all()
  2209. class PowerFeedBulkDeleteView(generic.BulkDeleteView):
  2210. queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack')
  2211. filterset = filtersets.PowerFeedFilterSet
  2212. table = tables.PowerFeedTable