views.py 101 KB

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