views.py 97 KB

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