views.py 110 KB

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