views.py 151 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478
  1. from django.conf import settings
  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 router, 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_lazy as _
  13. from django.views.generic import View
  14. from circuits.models import Circuit, CircuitTermination
  15. from dcim.ui import panels
  16. from extras.ui.panels import CustomFieldsPanel, ImageAttachmentsPanel, TagsPanel
  17. from extras.views import ObjectConfigContextView, ObjectRenderConfigView
  18. from ipam.models import ASN, IPAddress, Prefix, VLANGroup, VLAN
  19. from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
  20. from netbox.object_actions import *
  21. from netbox.ui import actions, layout
  22. from netbox.ui.panels import (
  23. CommentsPanel, JSONPanel, NestedGroupObjectPanel, ObjectsTablePanel, OrganizationalObjectPanel, RelatedObjectsPanel,
  24. TemplatePanel,
  25. )
  26. from netbox.views import generic
  27. from utilities.forms import ConfirmationForm
  28. from utilities.paginator import EnhancedPaginator, get_paginate_count
  29. from utilities.permissions import get_permission_for_model
  30. from utilities.query import count_related
  31. from utilities.query_functions import CollateAsChar
  32. from utilities.request import safe_for_redirect
  33. from utilities.views import (
  34. GetRelatedModelsMixin, GetReturnURLMixin, ObjectPermissionRequiredMixin, ViewTab, register_model_view
  35. )
  36. from virtualization.filtersets import VirtualMachineFilterSet
  37. from virtualization.forms import VirtualMachineFilterForm
  38. from virtualization.models import Cluster, VirtualMachine
  39. from virtualization.tables import VirtualMachineTable
  40. from wireless.models import WirelessLAN
  41. from . import filtersets, forms, tables
  42. from .choices import DeviceFaceChoices, InterfaceModeChoices
  43. from .models import *
  44. from .models.device_components import PortMapping
  45. from .object_actions import BulkAddComponents, BulkDisconnect
  46. CABLE_TERMINATION_TYPES = {
  47. 'dcim.consoleport': ConsolePort,
  48. 'dcim.consoleserverport': ConsoleServerPort,
  49. 'dcim.powerport': PowerPort,
  50. 'dcim.poweroutlet': PowerOutlet,
  51. 'dcim.interface': Interface,
  52. 'dcim.frontport': FrontPort,
  53. 'dcim.rearport': RearPort,
  54. 'dcim.powerfeed': PowerFeed,
  55. 'circuits.circuittermination': CircuitTermination,
  56. }
  57. class DeviceComponentsView(generic.ObjectChildrenView):
  58. queryset = Device.objects.all()
  59. def get_children(self, request, parent):
  60. return self.child_model.objects.restrict(request.user, 'view').filter(device=parent)
  61. class DeviceTypeComponentsView(generic.ObjectChildrenView):
  62. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDelete)
  63. queryset = DeviceType.objects.all()
  64. viewname = None # Used for return_url resolution
  65. def get_children(self, request, parent):
  66. return self.child_model.objects.restrict(request.user, 'view').filter(device_type=parent)
  67. def get_extra_context(self, request, instance):
  68. return {
  69. 'return_url': reverse(self.viewname, kwargs={'pk': instance.pk}),
  70. }
  71. class ModuleTypeComponentsView(generic.ObjectChildrenView):
  72. queryset = ModuleType.objects.all()
  73. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDelete)
  74. viewname = None # Used for return_url resolution
  75. def get_children(self, request, parent):
  76. return self.child_model.objects.restrict(request.user, 'view').filter(module_type=parent)
  77. def get_extra_context(self, request, instance):
  78. return {
  79. 'return_url': reverse(self.viewname, kwargs={'pk': instance.pk}),
  80. }
  81. class BulkDisconnectView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
  82. """
  83. An extendable view for disconnection console/power/interface components in bulk.
  84. """
  85. queryset = None
  86. template_name = 'dcim/bulk_disconnect.html'
  87. def __init__(self, *args, **kwargs):
  88. super().__init__(*args, **kwargs)
  89. # Create a new Form class from ConfirmationForm
  90. class _Form(ConfirmationForm):
  91. pk = ModelMultipleChoiceField(
  92. queryset=self.queryset,
  93. widget=MultipleHiddenInput()
  94. )
  95. self.form = _Form
  96. def get_required_permission(self):
  97. return get_permission_for_model(self.queryset.model, 'change')
  98. def post(self, request):
  99. selected_objects = []
  100. return_url = self.get_return_url(request)
  101. if '_confirm' in request.POST:
  102. form = self.form(request.POST)
  103. if form.is_valid():
  104. with transaction.atomic(using=router.db_for_write(Cable)):
  105. count = 0
  106. cable_ids = set()
  107. for obj in self.queryset.filter(pk__in=form.cleaned_data['pk']):
  108. if obj.cable:
  109. cable_ids.add(obj.cable.pk)
  110. count += 1
  111. for cable in Cable.objects.filter(pk__in=cable_ids):
  112. cable.delete()
  113. messages.success(request, _("Disconnected {count} {type}").format(
  114. count=count,
  115. type=self.queryset.model._meta.verbose_name_plural
  116. ))
  117. return redirect(return_url)
  118. else:
  119. form = self.form(initial={'pk': request.POST.getlist('pk')})
  120. selected_objects = self.queryset.filter(pk__in=form.initial['pk'])
  121. return render(request, self.template_name, {
  122. 'form': form,
  123. 'obj_type_plural': self.queryset.model._meta.verbose_name_plural,
  124. 'selected_objects': selected_objects,
  125. 'return_url': return_url,
  126. })
  127. class PathTraceView(generic.ObjectView):
  128. """
  129. Trace a cable path beginning from the given path endpoint (origin).
  130. """
  131. additional_permissions = ['dcim.view_cable']
  132. template_name = 'dcim/cable_trace.html'
  133. def dispatch(self, request, *args, **kwargs):
  134. model = kwargs.pop('model')
  135. self.queryset = model.objects.all()
  136. return super().dispatch(request, *args, **kwargs)
  137. def get_extra_context(self, request, instance):
  138. related_paths = []
  139. # If tracing a PathEndpoint, locate the CablePath (if one exists) by its origin
  140. if isinstance(instance, PathEndpoint):
  141. path = instance._path
  142. # Otherwise, find all CablePaths which traverse the specified object
  143. else:
  144. related_paths = CablePath.objects.filter(_nodes__contains=instance)
  145. # Check for specification of a particular path (when tracing pass-through ports)
  146. try:
  147. path_id = int(request.GET.get('cablepath_id'))
  148. except TypeError:
  149. path_id = None
  150. if path_id in list(related_paths.values_list('pk', flat=True)):
  151. path = CablePath.objects.get(pk=path_id)
  152. else:
  153. path = related_paths.first()
  154. # No paths found
  155. if path is None:
  156. return {
  157. 'path': None
  158. }
  159. # Get the total length of the cable and whether the length is definitive (fully defined)
  160. total_length, is_definitive = path.get_total_length() if path else (None, False)
  161. # Determine the path to the SVG trace image
  162. api_viewname = f"{path.origin_type.app_label}-api:{path.origin_type.model}-trace"
  163. svg_url = f"{reverse(api_viewname, kwargs={'pk': path.origins[0].pk})}?render=svg"
  164. return {
  165. 'path': path,
  166. 'related_paths': related_paths,
  167. 'total_length': total_length,
  168. 'is_definitive': is_definitive,
  169. 'svg_url': svg_url,
  170. }
  171. #
  172. # Regions
  173. #
  174. @register_model_view(Region, 'list', path='', detail=False)
  175. class RegionListView(generic.ObjectListView):
  176. queryset = Region.objects.add_related_count(
  177. Region.objects.all(),
  178. Site,
  179. 'region',
  180. 'site_count',
  181. cumulative=True
  182. )
  183. filterset = filtersets.RegionFilterSet
  184. filterset_form = forms.RegionFilterForm
  185. table = tables.RegionTable
  186. @register_model_view(Region)
  187. class RegionView(GetRelatedModelsMixin, generic.ObjectView):
  188. queryset = Region.objects.all()
  189. layout = layout.SimpleLayout(
  190. left_panels=[
  191. NestedGroupObjectPanel(),
  192. TagsPanel(),
  193. CustomFieldsPanel(),
  194. CommentsPanel(),
  195. ],
  196. right_panels=[
  197. RelatedObjectsPanel(),
  198. ],
  199. bottom_panels=[
  200. ObjectsTablePanel(
  201. model='dcim.Region',
  202. title=_('Child Regions'),
  203. filters={'parent_id': lambda ctx: ctx['object'].pk},
  204. actions=[
  205. actions.AddObject('dcim.Region', url_params={'parent': lambda ctx: ctx['object'].pk}),
  206. ],
  207. ),
  208. ]
  209. )
  210. def get_extra_context(self, request, instance):
  211. regions = instance.get_descendants(include_self=True)
  212. return {
  213. 'related_models': self.get_related_models(
  214. request,
  215. regions,
  216. omit=(Cluster, CircuitTermination, Prefix, WirelessLAN),
  217. extra=(
  218. (Location.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'),
  219. (Rack.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'),
  220. (
  221. Circuit.objects.restrict(request.user, 'view').filter(
  222. terminations___region=instance
  223. ).distinct(),
  224. 'region_id'
  225. ),
  226. (
  227. VLANGroup.objects.restrict(request.user, 'view').filter(
  228. scope_type=ContentType.objects.get_for_model(Region),
  229. scope_id__in=regions
  230. ).distinct(),
  231. 'region'
  232. ),
  233. # Handle these relations manually to avoid erroneous filter name resolution
  234. (
  235. CircuitTermination.objects.restrict(request.user, 'view').filter(_region__in=regions),
  236. 'region_id'
  237. ),
  238. (Cluster.objects.restrict(request.user, 'view').filter(_region__in=regions), 'region_id'),
  239. (Prefix.objects.restrict(request.user, 'view').filter(_region__in=regions), 'region_id'),
  240. (WirelessLAN.objects.restrict(request.user, 'view').filter(_region__in=regions), 'region_id'),
  241. ),
  242. ),
  243. }
  244. @register_model_view(Region, 'add', detail=False)
  245. @register_model_view(Region, 'edit')
  246. class RegionEditView(generic.ObjectEditView):
  247. queryset = Region.objects.all()
  248. form = forms.RegionForm
  249. @register_model_view(Region, 'delete')
  250. class RegionDeleteView(generic.ObjectDeleteView):
  251. queryset = Region.objects.all()
  252. @register_model_view(Region, 'bulk_import', path='import', detail=False)
  253. class RegionBulkImportView(generic.BulkImportView):
  254. queryset = Region.objects.all()
  255. model_form = forms.RegionImportForm
  256. @register_model_view(Region, 'bulk_edit', path='edit', detail=False)
  257. class RegionBulkEditView(generic.BulkEditView):
  258. queryset = Region.objects.add_related_count(
  259. Region.objects.all(),
  260. Site,
  261. 'region',
  262. 'site_count',
  263. cumulative=True
  264. )
  265. filterset = filtersets.RegionFilterSet
  266. table = tables.RegionTable
  267. form = forms.RegionBulkEditForm
  268. @register_model_view(Region, 'bulk_rename', path='rename', detail=False)
  269. class RegionBulkRenameView(generic.BulkRenameView):
  270. queryset = Region.objects.all()
  271. filterset = filtersets.RegionFilterSet
  272. @register_model_view(Region, 'bulk_delete', path='delete', detail=False)
  273. class RegionBulkDeleteView(generic.BulkDeleteView):
  274. queryset = Region.objects.add_related_count(
  275. Region.objects.all(),
  276. Site,
  277. 'region',
  278. 'site_count',
  279. cumulative=True
  280. )
  281. filterset = filtersets.RegionFilterSet
  282. table = tables.RegionTable
  283. #
  284. # Site groups
  285. #
  286. @register_model_view(SiteGroup, 'list', path='', detail=False)
  287. class SiteGroupListView(generic.ObjectListView):
  288. queryset = SiteGroup.objects.add_related_count(
  289. SiteGroup.objects.all(),
  290. Site,
  291. 'group',
  292. 'site_count',
  293. cumulative=True
  294. )
  295. filterset = filtersets.SiteGroupFilterSet
  296. filterset_form = forms.SiteGroupFilterForm
  297. table = tables.SiteGroupTable
  298. @register_model_view(SiteGroup)
  299. class SiteGroupView(GetRelatedModelsMixin, generic.ObjectView):
  300. queryset = SiteGroup.objects.all()
  301. layout = layout.SimpleLayout(
  302. left_panels=[
  303. NestedGroupObjectPanel(),
  304. TagsPanel(),
  305. CustomFieldsPanel(),
  306. CommentsPanel(),
  307. ],
  308. right_panels=[
  309. RelatedObjectsPanel(),
  310. ],
  311. bottom_panels=[
  312. ObjectsTablePanel(
  313. model='dcim.SiteGroup',
  314. title=_('Child Groups'),
  315. filters={'parent_id': lambda ctx: ctx['object'].pk},
  316. actions=[
  317. actions.AddObject('dcim.Region', url_params={'parent': lambda ctx: ctx['object'].pk}),
  318. ],
  319. ),
  320. ]
  321. )
  322. def get_extra_context(self, request, instance):
  323. groups = instance.get_descendants(include_self=True)
  324. return {
  325. 'related_models': self.get_related_models(
  326. request,
  327. groups,
  328. omit=(Cluster, CircuitTermination, Prefix, WirelessLAN),
  329. extra=(
  330. (Location.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
  331. (Rack.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
  332. (Device.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
  333. (VLAN.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
  334. (
  335. ASN.objects.restrict(request.user, 'view').filter(
  336. sites__group__in=groups
  337. ).distinct(),
  338. 'site_group_id'),
  339. (
  340. VirtualMachine.objects.restrict(request.user, 'view').filter(
  341. site__group__in=groups),
  342. 'site_group_id'
  343. ),
  344. (
  345. VLANGroup.objects.restrict(request.user, 'view').filter(
  346. scope_type=ContentType.objects.get_for_model(SiteGroup),
  347. scope_id__in=groups
  348. ).distinct(),
  349. 'site_group'
  350. ),
  351. (
  352. Circuit.objects.restrict(request.user, 'view').filter(
  353. terminations___site_group=instance
  354. ).distinct(),
  355. 'site_group_id'
  356. ),
  357. # Handle these relations manually to avoid erroneous filter name resolution
  358. (
  359. CircuitTermination.objects.restrict(request.user, 'view').filter(_site_group__in=groups),
  360. 'site_group_id'
  361. ),
  362. (
  363. Cluster.objects.restrict(request.user, 'view').filter(_site_group__in=groups),
  364. 'site_group_id'
  365. ),
  366. (
  367. Prefix.objects.restrict(request.user, 'view').filter(_site_group__in=groups),
  368. 'site_group_id'
  369. ),
  370. (
  371. WirelessLAN.objects.restrict(request.user, 'view').filter(_site_group__in=groups),
  372. 'site_group_id'
  373. ),
  374. ),
  375. ),
  376. }
  377. @register_model_view(SiteGroup, 'add', detail=False)
  378. @register_model_view(SiteGroup, 'edit')
  379. class SiteGroupEditView(generic.ObjectEditView):
  380. queryset = SiteGroup.objects.all()
  381. form = forms.SiteGroupForm
  382. @register_model_view(SiteGroup, 'delete')
  383. class SiteGroupDeleteView(generic.ObjectDeleteView):
  384. queryset = SiteGroup.objects.all()
  385. @register_model_view(SiteGroup, 'bulk_import', path='import', detail=False)
  386. class SiteGroupBulkImportView(generic.BulkImportView):
  387. queryset = SiteGroup.objects.all()
  388. model_form = forms.SiteGroupImportForm
  389. @register_model_view(SiteGroup, 'bulk_edit', path='edit', detail=False)
  390. class SiteGroupBulkEditView(generic.BulkEditView):
  391. queryset = SiteGroup.objects.add_related_count(
  392. SiteGroup.objects.all(),
  393. Site,
  394. 'group',
  395. 'site_count',
  396. cumulative=True
  397. )
  398. filterset = filtersets.SiteGroupFilterSet
  399. table = tables.SiteGroupTable
  400. form = forms.SiteGroupBulkEditForm
  401. @register_model_view(SiteGroup, 'bulk_rename', path='rename', detail=False)
  402. class SiteGroupBulkRenameView(generic.BulkRenameView):
  403. queryset = SiteGroup.objects.all()
  404. filterset = filtersets.SiteGroupFilterSet
  405. @register_model_view(SiteGroup, 'bulk_delete', path='delete', detail=False)
  406. class SiteGroupBulkDeleteView(generic.BulkDeleteView):
  407. queryset = SiteGroup.objects.add_related_count(
  408. SiteGroup.objects.all(),
  409. Site,
  410. 'group',
  411. 'site_count',
  412. cumulative=True
  413. )
  414. filterset = filtersets.SiteGroupFilterSet
  415. table = tables.SiteGroupTable
  416. #
  417. # Sites
  418. #
  419. @register_model_view(Site, 'list', path='', detail=False)
  420. class SiteListView(generic.ObjectListView):
  421. queryset = Site.objects.annotate(
  422. device_count=count_related(Device, 'site'),
  423. asn_count=count_related(ASN, 'sites')
  424. )
  425. filterset = filtersets.SiteFilterSet
  426. filterset_form = forms.SiteFilterForm
  427. table = tables.SiteTable
  428. @register_model_view(Site)
  429. class SiteView(GetRelatedModelsMixin, generic.ObjectView):
  430. queryset = Site.objects.prefetch_related('tenant__group')
  431. layout = layout.SimpleLayout(
  432. left_panels=[
  433. panels.SitePanel(),
  434. CustomFieldsPanel(),
  435. TagsPanel(),
  436. CommentsPanel(),
  437. ],
  438. right_panels=[
  439. RelatedObjectsPanel(),
  440. ImageAttachmentsPanel(),
  441. ],
  442. bottom_panels=[
  443. ObjectsTablePanel(
  444. model='dcim.Location',
  445. filters={'site_id': lambda ctx: ctx['object'].pk},
  446. actions=[
  447. actions.AddObject('dcim.Location', url_params={'site': lambda ctx: ctx['object'].pk}),
  448. ],
  449. ),
  450. ObjectsTablePanel(
  451. model='dcim.Device',
  452. title=_('Non-Racked Devices'),
  453. filters={
  454. 'site_id': lambda ctx: ctx['object'].pk,
  455. 'rack_id': settings.FILTERS_NULL_CHOICE_VALUE,
  456. 'parent_bay_id': settings.FILTERS_NULL_CHOICE_VALUE,
  457. },
  458. actions=[
  459. actions.AddObject('dcim.Device', url_params={'site': lambda ctx: ctx['object'].pk}),
  460. ],
  461. ),
  462. ]
  463. )
  464. def get_extra_context(self, request, instance):
  465. return {
  466. 'related_models': self.get_related_models(
  467. request,
  468. instance,
  469. omit=(CableTermination, CircuitTermination, Cluster, Prefix, WirelessLAN),
  470. extra=(
  471. (VLANGroup.objects.restrict(request.user, 'view').filter(
  472. scope_type=ContentType.objects.get_for_model(Site),
  473. scope_id=instance.pk
  474. ), 'site'),
  475. (ASN.objects.restrict(request.user, 'view').filter(sites=instance), 'site_id'),
  476. (
  477. Circuit.objects.restrict(request.user, 'view').filter(terminations___site=instance).distinct(),
  478. 'site_id'
  479. ),
  480. # Handle these relations manually to avoid erroneous filter name resolution
  481. (Cluster.objects.restrict(request.user, 'view').filter(_site=instance), 'site_id'),
  482. (Prefix.objects.restrict(request.user, 'view').filter(_site=instance), 'site_id'),
  483. (WirelessLAN.objects.restrict(request.user, 'view').filter(_site=instance), 'site_id'),
  484. (CircuitTermination.objects.restrict(request.user, 'view').filter(_site=instance), 'site_id'),
  485. ),
  486. ),
  487. }
  488. @register_model_view(Site, 'add', detail=False)
  489. @register_model_view(Site, 'edit')
  490. class SiteEditView(generic.ObjectEditView):
  491. queryset = Site.objects.all()
  492. form = forms.SiteForm
  493. @register_model_view(Site, 'delete')
  494. class SiteDeleteView(generic.ObjectDeleteView):
  495. queryset = Site.objects.all()
  496. @register_model_view(Site, 'bulk_import', path='import', detail=False)
  497. class SiteBulkImportView(generic.BulkImportView):
  498. queryset = Site.objects.all()
  499. model_form = forms.SiteImportForm
  500. @register_model_view(Site, 'bulk_edit', path='edit', detail=False)
  501. class SiteBulkEditView(generic.BulkEditView):
  502. queryset = Site.objects.all()
  503. filterset = filtersets.SiteFilterSet
  504. table = tables.SiteTable
  505. form = forms.SiteBulkEditForm
  506. @register_model_view(Site, 'bulk_rename', path='rename', detail=False)
  507. class SiteBulkRenameView(generic.BulkRenameView):
  508. queryset = Site.objects.all()
  509. filterset = filtersets.SiteFilterSet
  510. @register_model_view(Site, 'bulk_delete', path='delete', detail=False)
  511. class SiteBulkDeleteView(generic.BulkDeleteView):
  512. queryset = Site.objects.all()
  513. filterset = filtersets.SiteFilterSet
  514. table = tables.SiteTable
  515. #
  516. # Locations
  517. #
  518. @register_model_view(Location, 'list', path='', detail=False)
  519. class LocationListView(generic.ObjectListView):
  520. queryset = Location.objects.add_related_count(
  521. Location.objects.add_related_count(
  522. Location.objects.add_related_count(
  523. Location.objects.all(),
  524. Device,
  525. 'location',
  526. 'device_count',
  527. cumulative=True
  528. ),
  529. Rack,
  530. 'location',
  531. 'rack_count',
  532. cumulative=True
  533. ),
  534. VLANGroup,
  535. 'location',
  536. 'vlangroup_count',
  537. cumulative=True
  538. )
  539. filterset = filtersets.LocationFilterSet
  540. filterset_form = forms.LocationFilterForm
  541. table = tables.LocationTable
  542. @register_model_view(Location)
  543. class LocationView(GetRelatedModelsMixin, generic.ObjectView):
  544. queryset = Location.objects.all()
  545. layout = layout.SimpleLayout(
  546. left_panels=[
  547. panels.LocationPanel(),
  548. TagsPanel(),
  549. CustomFieldsPanel(),
  550. CommentsPanel(),
  551. ],
  552. right_panels=[
  553. RelatedObjectsPanel(),
  554. ImageAttachmentsPanel(),
  555. ],
  556. bottom_panels=[
  557. ObjectsTablePanel(
  558. model='dcim.Location',
  559. title=_('Child Locations'),
  560. filters={'parent_id': lambda ctx: ctx['object'].pk},
  561. actions=[
  562. actions.AddObject(
  563. 'dcim.Location',
  564. url_params={
  565. 'site': lambda ctx: ctx['object'].site_id,
  566. 'parent': lambda ctx: ctx['object'].pk,
  567. }
  568. ),
  569. ],
  570. ),
  571. ObjectsTablePanel(
  572. model='dcim.Device',
  573. title=_('Non-Racked Devices'),
  574. filters={
  575. 'location_id': lambda ctx: ctx['object'].pk,
  576. 'rack_id': settings.FILTERS_NULL_CHOICE_VALUE,
  577. 'parent_bay_id': settings.FILTERS_NULL_CHOICE_VALUE,
  578. },
  579. actions=[
  580. actions.AddObject(
  581. 'dcim.Device',
  582. url_params={
  583. 'site': lambda ctx: ctx['object'].site_id,
  584. 'parent': lambda ctx: ctx['object'].pk,
  585. }
  586. ),
  587. ],
  588. ),
  589. ]
  590. )
  591. def get_extra_context(self, request, instance):
  592. locations = instance.get_descendants(include_self=True)
  593. location_content_type = ContentType.objects.get_for_model(instance)
  594. return {
  595. 'related_models': self.get_related_models(
  596. request,
  597. locations,
  598. omit=[CableTermination, CircuitTermination, Cluster, Prefix, WirelessLAN],
  599. extra=(
  600. (
  601. Circuit.objects.restrict(request.user, 'view').filter(
  602. terminations___location=instance
  603. ).distinct(),
  604. 'location_id'
  605. ),
  606. # Handle these relations manually to avoid erroneous filter name resolution
  607. (
  608. CircuitTermination.objects.restrict(request.user, 'view').filter(_location=instance),
  609. 'location_id'
  610. ),
  611. (Cluster.objects.restrict(request.user, 'view').filter(_location=instance), 'location_id'),
  612. (Prefix.objects.restrict(request.user, 'view').filter(_location=instance), 'location_id'),
  613. (WirelessLAN.objects.restrict(request.user, 'view').filter(_location=instance), 'location_id'),
  614. (VLANGroup.objects.restrict(request.user, 'view').filter(
  615. scope_type_id=location_content_type.id, scope_id=instance.id), 'location'),
  616. ),
  617. ),
  618. }
  619. @register_model_view(Location, 'add', detail=False)
  620. @register_model_view(Location, 'edit')
  621. class LocationEditView(generic.ObjectEditView):
  622. queryset = Location.objects.all()
  623. form = forms.LocationForm
  624. @register_model_view(Location, 'delete')
  625. class LocationDeleteView(generic.ObjectDeleteView):
  626. queryset = Location.objects.all()
  627. @register_model_view(Location, 'bulk_import', path='import', detail=False)
  628. class LocationBulkImportView(generic.BulkImportView):
  629. queryset = Location.objects.all()
  630. model_form = forms.LocationImportForm
  631. @register_model_view(Location, 'bulk_edit', path='edit', detail=False)
  632. class LocationBulkEditView(generic.BulkEditView):
  633. queryset = Location.objects.add_related_count(
  634. Location.objects.all(),
  635. Rack,
  636. 'location',
  637. 'rack_count',
  638. cumulative=True
  639. ).prefetch_related('site')
  640. filterset = filtersets.LocationFilterSet
  641. table = tables.LocationTable
  642. form = forms.LocationBulkEditForm
  643. @register_model_view(Location, 'bulk_rename', path='rename', detail=False)
  644. class LocationBulkRenameView(generic.BulkRenameView):
  645. queryset = Location.objects.all()
  646. filterset = filtersets.LocationFilterSet
  647. @register_model_view(Location, 'bulk_delete', path='delete', detail=False)
  648. class LocationBulkDeleteView(generic.BulkDeleteView):
  649. queryset = Location.objects.add_related_count(
  650. Location.objects.all(),
  651. Rack,
  652. 'location',
  653. 'rack_count',
  654. cumulative=True
  655. ).prefetch_related('site')
  656. filterset = filtersets.LocationFilterSet
  657. table = tables.LocationTable
  658. #
  659. # Rack roles
  660. #
  661. @register_model_view(RackRole, 'list', path='', detail=False)
  662. class RackRoleListView(generic.ObjectListView):
  663. queryset = RackRole.objects.annotate(
  664. rack_count=count_related(Rack, 'role')
  665. )
  666. filterset = filtersets.RackRoleFilterSet
  667. filterset_form = forms.RackRoleFilterForm
  668. table = tables.RackRoleTable
  669. @register_model_view(RackRole)
  670. class RackRoleView(GetRelatedModelsMixin, generic.ObjectView):
  671. queryset = RackRole.objects.all()
  672. layout = layout.SimpleLayout(
  673. left_panels=[
  674. panels.RackRolePanel(),
  675. TagsPanel(),
  676. ],
  677. right_panels=[
  678. RelatedObjectsPanel(),
  679. CustomFieldsPanel(),
  680. ],
  681. )
  682. def get_extra_context(self, request, instance):
  683. return {
  684. 'related_models': self.get_related_models(request, instance),
  685. }
  686. @register_model_view(RackRole, 'add', detail=False)
  687. @register_model_view(RackRole, 'edit')
  688. class RackRoleEditView(generic.ObjectEditView):
  689. queryset = RackRole.objects.all()
  690. form = forms.RackRoleForm
  691. @register_model_view(RackRole, 'delete')
  692. class RackRoleDeleteView(generic.ObjectDeleteView):
  693. queryset = RackRole.objects.all()
  694. @register_model_view(RackRole, 'bulk_import', path='import', detail=False)
  695. class RackRoleBulkImportView(generic.BulkImportView):
  696. queryset = RackRole.objects.all()
  697. model_form = forms.RackRoleImportForm
  698. @register_model_view(RackRole, 'bulk_edit', path='edit', detail=False)
  699. class RackRoleBulkEditView(generic.BulkEditView):
  700. queryset = RackRole.objects.annotate(
  701. rack_count=count_related(Rack, 'role')
  702. )
  703. filterset = filtersets.RackRoleFilterSet
  704. table = tables.RackRoleTable
  705. form = forms.RackRoleBulkEditForm
  706. @register_model_view(RackRole, 'bulk_rename', path='rename', detail=False)
  707. class RackRoleBulkRenameView(generic.BulkRenameView):
  708. queryset = RackRole.objects.all()
  709. filterset = filtersets.RackRoleFilterSet
  710. @register_model_view(RackRole, 'bulk_delete', path='delete', detail=False)
  711. class RackRoleBulkDeleteView(generic.BulkDeleteView):
  712. queryset = RackRole.objects.annotate(
  713. rack_count=count_related(Rack, 'role')
  714. )
  715. filterset = filtersets.RackRoleFilterSet
  716. table = tables.RackRoleTable
  717. #
  718. # RackTypes
  719. #
  720. @register_model_view(RackType, 'list', path='', detail=False)
  721. class RackTypeListView(generic.ObjectListView):
  722. queryset = RackType.objects.all()
  723. filterset = filtersets.RackTypeFilterSet
  724. filterset_form = forms.RackTypeFilterForm
  725. table = tables.RackTypeTable
  726. @register_model_view(RackType)
  727. class RackTypeView(GetRelatedModelsMixin, generic.ObjectView):
  728. template_name = 'generic/object.html'
  729. queryset = RackType.objects.all()
  730. layout = layout.SimpleLayout(
  731. left_panels=[
  732. panels.RackTypePanel(),
  733. panels.RackDimensionsPanel(title=_('Dimensions')),
  734. TagsPanel(),
  735. CommentsPanel(),
  736. ],
  737. right_panels=[
  738. panels.RackNumberingPanel(title=_('Numbering')),
  739. panels.RackWeightPanel(title=_('Weight'), exclude=['total_weight']),
  740. CustomFieldsPanel(),
  741. RelatedObjectsPanel(),
  742. ],
  743. )
  744. def get_extra_context(self, request, instance):
  745. return {
  746. 'related_models': self.get_related_models(request, instance),
  747. }
  748. @register_model_view(RackType, 'add', detail=False)
  749. @register_model_view(RackType, 'edit')
  750. class RackTypeEditView(generic.ObjectEditView):
  751. queryset = RackType.objects.all()
  752. form = forms.RackTypeForm
  753. @register_model_view(RackType, 'delete')
  754. class RackTypeDeleteView(generic.ObjectDeleteView):
  755. queryset = RackType.objects.all()
  756. @register_model_view(RackType, 'bulk_import', path='import', detail=False)
  757. class RackTypeBulkImportView(generic.BulkImportView):
  758. queryset = RackType.objects.all()
  759. model_form = forms.RackTypeImportForm
  760. @register_model_view(RackType, 'bulk_edit', path='edit', detail=False)
  761. class RackTypeBulkEditView(generic.BulkEditView):
  762. queryset = RackType.objects.all()
  763. filterset = filtersets.RackTypeFilterSet
  764. table = tables.RackTypeTable
  765. form = forms.RackTypeBulkEditForm
  766. @register_model_view(RackType, 'bulk_rename', path='rename', detail=False)
  767. class RackTypeBulkRenameView(generic.BulkRenameView):
  768. queryset = RackType.objects.all()
  769. field_name = 'model'
  770. filterset = filtersets.RackTypeFilterSet
  771. @register_model_view(RackType, 'bulk_delete', path='delete', detail=False)
  772. class RackTypeBulkDeleteView(generic.BulkDeleteView):
  773. queryset = RackType.objects.all()
  774. filterset = filtersets.RackTypeFilterSet
  775. table = tables.RackTypeTable
  776. #
  777. # Racks
  778. #
  779. @register_model_view(Rack, 'list', path='', detail=False)
  780. class RackListView(generic.ObjectListView):
  781. queryset = Rack.objects.annotate(
  782. device_count=count_related(Device, 'rack')
  783. )
  784. filterset = filtersets.RackFilterSet
  785. filterset_form = forms.RackFilterForm
  786. table = tables.RackTable
  787. template_name = 'dcim/rack_list.html'
  788. class RackElevationListView(generic.ObjectListView):
  789. """
  790. Display a set of rack elevations side-by-side.
  791. """
  792. queryset = Rack.objects.prefetch_related('role')
  793. def get(self, request):
  794. racks = filtersets.RackFilterSet(request.GET, self.queryset).qs
  795. total_count = racks.count()
  796. # Ordering
  797. ORDERING_CHOICES = {
  798. 'name': 'Name (A-Z)',
  799. '-name': 'Name (Z-A)',
  800. 'facility_id': 'Facility ID (A-Z)',
  801. '-facility_id': 'Facility ID (Z-A)',
  802. }
  803. sort = request.GET.get('sort', 'name')
  804. if sort not in ORDERING_CHOICES:
  805. sort = 'name'
  806. racks = racks.order_by(sort)
  807. # Pagination
  808. per_page = get_paginate_count(request)
  809. page_number = request.GET.get('page', 1)
  810. paginator = EnhancedPaginator(racks, per_page)
  811. try:
  812. page = paginator.page(page_number)
  813. except PageNotAnInteger:
  814. page = paginator.page(1)
  815. except EmptyPage:
  816. page = paginator.page(paginator.num_pages)
  817. # Determine rack face
  818. rack_face = request.GET.get('face', DeviceFaceChoices.FACE_FRONT)
  819. if rack_face not in DeviceFaceChoices.values():
  820. rack_face = DeviceFaceChoices.FACE_FRONT
  821. return render(request, 'dcim/rack_elevation_list.html', {
  822. 'paginator': paginator,
  823. 'page': page,
  824. 'total_count': total_count,
  825. 'sort': sort,
  826. 'sort_display_name': ORDERING_CHOICES[sort],
  827. 'sort_choices': ORDERING_CHOICES,
  828. 'rack_face': rack_face,
  829. 'filter_form': forms.RackElevationFilterForm(request.GET),
  830. 'model': self.queryset.model,
  831. })
  832. @register_model_view(Rack)
  833. class RackView(GetRelatedModelsMixin, generic.ObjectView):
  834. queryset = Rack.objects.prefetch_related('site__region', 'tenant__group', 'location', 'role')
  835. layout = layout.SimpleLayout(
  836. left_panels=[
  837. panels.RackPanel(),
  838. panels.RackDimensionsPanel(title=_('Dimensions')),
  839. panels.RackNumberingPanel(title=_('Numbering')),
  840. panels.RackWeightPanel(title=_('Weight')),
  841. CustomFieldsPanel(),
  842. TagsPanel(),
  843. CommentsPanel(),
  844. ImageAttachmentsPanel(),
  845. ],
  846. right_panels=[
  847. TemplatePanel('dcim/panels/rack_elevations.html'),
  848. RelatedObjectsPanel(),
  849. ],
  850. )
  851. def get_extra_context(self, request, instance):
  852. peer_racks = Rack.objects.restrict(request.user, 'view').filter(site=instance.site)
  853. if instance.location:
  854. peer_racks = peer_racks.filter(location=instance.location)
  855. else:
  856. peer_racks = peer_racks.filter(location__isnull=True)
  857. next_rack = peer_racks.filter(name__gt=instance.name).first()
  858. prev_rack = peer_racks.filter(name__lt=instance.name).reverse().first()
  859. # Determine any additional parameters to pass when embedding the rack elevations
  860. svg_extra = '&'.join([
  861. f'highlight=id:{pk}' for pk in request.GET.getlist('device')
  862. ])
  863. return {
  864. 'related_models': self.get_related_models(
  865. request,
  866. instance,
  867. omit=(CableTermination,),
  868. extra=(
  869. (
  870. VLANGroup.objects.restrict(request.user, 'view').filter(
  871. scope_type=ContentType.objects.get_for_model(Rack),
  872. scope_id=instance.pk
  873. ), 'rack'),
  874. ),
  875. ),
  876. 'next_rack': next_rack,
  877. 'prev_rack': prev_rack,
  878. 'svg_extra': svg_extra,
  879. 'peer_racks': peer_racks,
  880. }
  881. @register_model_view(Rack, 'reservations')
  882. class RackRackReservationsView(generic.ObjectChildrenView):
  883. queryset = Rack.objects.all()
  884. child_model = RackReservation
  885. table = tables.RackReservationTable
  886. filterset = filtersets.RackReservationFilterSet
  887. filterset_form = forms.RackReservationFilterForm
  888. template_name = 'dcim/rack/reservations.html'
  889. tab = ViewTab(
  890. label=_('Reservations'),
  891. badge=lambda obj: obj.reservations.count(),
  892. permission='dcim.view_rackreservation',
  893. weight=510
  894. )
  895. def get_children(self, request, parent):
  896. return parent.reservations.restrict(request.user, 'view')
  897. @register_model_view(Rack, 'nonracked_devices', 'nonracked-devices')
  898. class RackNonRackedView(generic.ObjectChildrenView):
  899. queryset = Rack.objects.all()
  900. child_model = Device
  901. table = tables.DeviceTable
  902. filterset = filtersets.DeviceFilterSet
  903. filterset_form = forms.DeviceFilterForm
  904. template_name = 'dcim/rack/non_racked_devices.html'
  905. tab = ViewTab(
  906. label=_('Non-Racked Devices'),
  907. badge=lambda obj: obj.devices.filter(rack=obj, position__isnull=True, parent_bay__isnull=True).count(),
  908. weight=500,
  909. permission='dcim.view_device',
  910. )
  911. def get_children(self, request, parent):
  912. return parent.devices.restrict(request.user, 'view').filter(
  913. rack=parent, position__isnull=True, parent_bay__isnull=True
  914. )
  915. @register_model_view(Rack, 'add', detail=False)
  916. @register_model_view(Rack, 'edit')
  917. class RackEditView(generic.ObjectEditView):
  918. queryset = Rack.objects.all()
  919. form = forms.RackForm
  920. @register_model_view(Rack, 'delete')
  921. class RackDeleteView(generic.ObjectDeleteView):
  922. queryset = Rack.objects.all()
  923. @register_model_view(Rack, 'bulk_import', path='import', detail=False)
  924. class RackBulkImportView(generic.BulkImportView):
  925. queryset = Rack.objects.all()
  926. model_form = forms.RackImportForm
  927. @register_model_view(Rack, 'bulk_edit', path='edit', detail=False)
  928. class RackBulkEditView(generic.BulkEditView):
  929. queryset = Rack.objects.all()
  930. filterset = filtersets.RackFilterSet
  931. table = tables.RackTable
  932. form = forms.RackBulkEditForm
  933. @register_model_view(Rack, 'bulk_rename', path='rename', detail=False)
  934. class RackBulkRenameView(generic.BulkRenameView):
  935. queryset = Rack.objects.all()
  936. filterset = filtersets.RackFilterSet
  937. @register_model_view(Rack, 'bulk_delete', path='delete', detail=False)
  938. class RackBulkDeleteView(generic.BulkDeleteView):
  939. queryset = Rack.objects.all()
  940. filterset = filtersets.RackFilterSet
  941. table = tables.RackTable
  942. #
  943. # Rack reservations
  944. #
  945. @register_model_view(RackReservation, 'list', path='', detail=False)
  946. class RackReservationListView(generic.ObjectListView):
  947. queryset = RackReservation.objects.all()
  948. filterset = filtersets.RackReservationFilterSet
  949. filterset_form = forms.RackReservationFilterForm
  950. table = tables.RackReservationTable
  951. actions = (AddObject, BulkImport, BulkExport, BulkEdit, BulkDelete)
  952. @register_model_view(RackReservation)
  953. class RackReservationView(generic.ObjectView):
  954. queryset = RackReservation.objects.all()
  955. layout = layout.SimpleLayout(
  956. left_panels=[
  957. panels.RackPanel(accessor='object.rack', only=['region', 'site', 'location', 'name']),
  958. panels.RackReservationPanel(title=_('Reservation')),
  959. CustomFieldsPanel(),
  960. TagsPanel(),
  961. CommentsPanel(),
  962. ],
  963. right_panels=[
  964. TemplatePanel(template_name='dcim/panels/rack_reservation_elevations.html'),
  965. RelatedObjectsPanel(),
  966. ],
  967. )
  968. @register_model_view(RackReservation, 'add', detail=False)
  969. @register_model_view(RackReservation, 'edit')
  970. class RackReservationEditView(generic.ObjectEditView):
  971. queryset = RackReservation.objects.all()
  972. form = forms.RackReservationForm
  973. def alter_object(self, obj, request, args, kwargs):
  974. if not obj.pk:
  975. if 'rack' in request.GET:
  976. obj.rack = get_object_or_404(Rack, pk=request.GET.get('rack'))
  977. obj.user = request.user
  978. return obj
  979. @register_model_view(RackReservation, 'delete')
  980. class RackReservationDeleteView(generic.ObjectDeleteView):
  981. queryset = RackReservation.objects.all()
  982. @register_model_view(RackReservation, 'bulk_import', path='import', detail=False)
  983. class RackReservationImportView(generic.BulkImportView):
  984. queryset = RackReservation.objects.all()
  985. model_form = forms.RackReservationImportForm
  986. def save_object(self, object_form, request):
  987. """
  988. Assign the currently authenticated user to the RackReservation.
  989. """
  990. instance = object_form.save(commit=False)
  991. instance.user = request.user
  992. instance.save()
  993. return instance
  994. @register_model_view(RackReservation, 'bulk_edit', path='edit', detail=False)
  995. class RackReservationBulkEditView(generic.BulkEditView):
  996. queryset = RackReservation.objects.all()
  997. filterset = filtersets.RackReservationFilterSet
  998. table = tables.RackReservationTable
  999. form = forms.RackReservationBulkEditForm
  1000. @register_model_view(RackReservation, 'bulk_delete', path='delete', detail=False)
  1001. class RackReservationBulkDeleteView(generic.BulkDeleteView):
  1002. queryset = RackReservation.objects.all()
  1003. filterset = filtersets.RackReservationFilterSet
  1004. table = tables.RackReservationTable
  1005. #
  1006. # Manufacturers
  1007. #
  1008. @register_model_view(Manufacturer, 'list', path='', detail=False)
  1009. class ManufacturerListView(generic.ObjectListView):
  1010. queryset = Manufacturer.objects.annotate(
  1011. racktype_count=count_related(RackType, 'manufacturer'),
  1012. devicetype_count=count_related(DeviceType, 'manufacturer'),
  1013. moduletype_count=count_related(ModuleType, 'manufacturer'),
  1014. inventoryitem_count=count_related(InventoryItem, 'manufacturer'),
  1015. platform_count=count_related(Platform, 'manufacturer')
  1016. )
  1017. filterset = filtersets.ManufacturerFilterSet
  1018. filterset_form = forms.ManufacturerFilterForm
  1019. table = tables.ManufacturerTable
  1020. @register_model_view(Manufacturer)
  1021. class ManufacturerView(GetRelatedModelsMixin, generic.ObjectView):
  1022. queryset = Manufacturer.objects.all()
  1023. layout = layout.SimpleLayout(
  1024. left_panels=[OrganizationalObjectPanel(), TagsPanel()],
  1025. right_panels=[RelatedObjectsPanel(), CustomFieldsPanel(), CommentsPanel()],
  1026. )
  1027. def get_extra_context(self, request, instance):
  1028. return {
  1029. 'related_models': self.get_related_models(request, instance, [InventoryItemTemplate]),
  1030. }
  1031. @register_model_view(Manufacturer, 'add', detail=False)
  1032. @register_model_view(Manufacturer, 'edit')
  1033. class ManufacturerEditView(generic.ObjectEditView):
  1034. queryset = Manufacturer.objects.all()
  1035. form = forms.ManufacturerForm
  1036. @register_model_view(Manufacturer, 'delete')
  1037. class ManufacturerDeleteView(generic.ObjectDeleteView):
  1038. queryset = Manufacturer.objects.all()
  1039. @register_model_view(Manufacturer, 'bulk_import', path='import', detail=False)
  1040. class ManufacturerBulkImportView(generic.BulkImportView):
  1041. queryset = Manufacturer.objects.all()
  1042. model_form = forms.ManufacturerImportForm
  1043. @register_model_view(Manufacturer, 'bulk_edit', path='edit', detail=False)
  1044. class ManufacturerBulkEditView(generic.BulkEditView):
  1045. queryset = Manufacturer.objects.annotate(
  1046. devicetype_count=count_related(DeviceType, 'manufacturer'),
  1047. moduletype_count=count_related(ModuleType, 'manufacturer'),
  1048. inventoryitem_count=count_related(InventoryItem, 'manufacturer'),
  1049. platform_count=count_related(Platform, 'manufacturer')
  1050. )
  1051. filterset = filtersets.ManufacturerFilterSet
  1052. table = tables.ManufacturerTable
  1053. form = forms.ManufacturerBulkEditForm
  1054. @register_model_view(Manufacturer, 'bulk_rename', path='rename', detail=False)
  1055. class ManufacturerBulkRenameView(generic.BulkRenameView):
  1056. queryset = Manufacturer.objects.all()
  1057. filterset = filtersets.ManufacturerFilterSet
  1058. @register_model_view(Manufacturer, 'bulk_delete', path='delete', detail=False)
  1059. class ManufacturerBulkDeleteView(generic.BulkDeleteView):
  1060. queryset = Manufacturer.objects.annotate(
  1061. devicetype_count=count_related(DeviceType, 'manufacturer'),
  1062. moduletype_count=count_related(ModuleType, 'manufacturer'),
  1063. inventoryitem_count=count_related(InventoryItem, 'manufacturer'),
  1064. platform_count=count_related(Platform, 'manufacturer')
  1065. )
  1066. filterset = filtersets.ManufacturerFilterSet
  1067. table = tables.ManufacturerTable
  1068. #
  1069. # Device types
  1070. #
  1071. @register_model_view(DeviceType, 'list', path='', detail=False)
  1072. class DeviceTypeListView(generic.ObjectListView):
  1073. queryset = DeviceType.objects.all()
  1074. filterset = filtersets.DeviceTypeFilterSet
  1075. filterset_form = forms.DeviceTypeFilterForm
  1076. table = tables.DeviceTypeTable
  1077. @register_model_view(DeviceType)
  1078. class DeviceTypeView(GetRelatedModelsMixin, generic.ObjectView):
  1079. queryset = DeviceType.objects.all()
  1080. layout = layout.SimpleLayout(
  1081. left_panels=[
  1082. panels.DeviceTypePanel(),
  1083. TagsPanel(),
  1084. ],
  1085. right_panels=[
  1086. RelatedObjectsPanel(),
  1087. CustomFieldsPanel(),
  1088. CommentsPanel(),
  1089. ImageAttachmentsPanel(),
  1090. ],
  1091. )
  1092. def get_extra_context(self, request, instance):
  1093. return {
  1094. 'related_models': self.get_related_models(request, instance, omit=[
  1095. ConsolePortTemplate, ConsoleServerPortTemplate, DeviceBayTemplate, FrontPortTemplate,
  1096. InventoryItemTemplate, InterfaceTemplate, ModuleBayTemplate, PowerOutletTemplate, PowerPortTemplate,
  1097. RearPortTemplate,
  1098. ]),
  1099. }
  1100. @register_model_view(DeviceType, 'add', detail=False)
  1101. @register_model_view(DeviceType, 'edit')
  1102. class DeviceTypeEditView(generic.ObjectEditView):
  1103. queryset = DeviceType.objects.all()
  1104. form = forms.DeviceTypeForm
  1105. @register_model_view(DeviceType, 'delete')
  1106. class DeviceTypeDeleteView(generic.ObjectDeleteView):
  1107. queryset = DeviceType.objects.all()
  1108. @register_model_view(DeviceType, 'consoleports', path='console-ports')
  1109. class DeviceTypeConsolePortsView(DeviceTypeComponentsView):
  1110. child_model = ConsolePortTemplate
  1111. table = tables.ConsolePortTemplateTable
  1112. filterset = filtersets.ConsolePortTemplateFilterSet
  1113. viewname = 'dcim:devicetype_consoleports'
  1114. tab = ViewTab(
  1115. label=_('Console Ports'),
  1116. badge=lambda obj: obj.console_port_template_count,
  1117. permission='dcim.view_consoleporttemplate',
  1118. weight=550,
  1119. hide_if_empty=True
  1120. )
  1121. @register_model_view(DeviceType, 'consoleserverports', path='console-server-ports')
  1122. class DeviceTypeConsoleServerPortsView(DeviceTypeComponentsView):
  1123. child_model = ConsoleServerPortTemplate
  1124. table = tables.ConsoleServerPortTemplateTable
  1125. filterset = filtersets.ConsoleServerPortTemplateFilterSet
  1126. viewname = 'dcim:devicetype_consoleserverports'
  1127. tab = ViewTab(
  1128. label=_('Console Server Ports'),
  1129. badge=lambda obj: obj.console_server_port_template_count,
  1130. permission='dcim.view_consoleserverporttemplate',
  1131. weight=560,
  1132. hide_if_empty=True
  1133. )
  1134. @register_model_view(DeviceType, 'powerports', path='power-ports')
  1135. class DeviceTypePowerPortsView(DeviceTypeComponentsView):
  1136. child_model = PowerPortTemplate
  1137. table = tables.PowerPortTemplateTable
  1138. filterset = filtersets.PowerPortTemplateFilterSet
  1139. viewname = 'dcim:devicetype_powerports'
  1140. tab = ViewTab(
  1141. label=_('Power Ports'),
  1142. badge=lambda obj: obj.power_port_template_count,
  1143. permission='dcim.view_powerporttemplate',
  1144. weight=570,
  1145. hide_if_empty=True
  1146. )
  1147. @register_model_view(DeviceType, 'poweroutlets', path='power-outlets')
  1148. class DeviceTypePowerOutletsView(DeviceTypeComponentsView):
  1149. child_model = PowerOutletTemplate
  1150. table = tables.PowerOutletTemplateTable
  1151. filterset = filtersets.PowerOutletTemplateFilterSet
  1152. viewname = 'dcim:devicetype_poweroutlets'
  1153. tab = ViewTab(
  1154. label=_('Power Outlets'),
  1155. badge=lambda obj: obj.power_outlet_template_count,
  1156. permission='dcim.view_poweroutlettemplate',
  1157. weight=580,
  1158. hide_if_empty=True
  1159. )
  1160. @register_model_view(DeviceType, 'interfaces')
  1161. class DeviceTypeInterfacesView(DeviceTypeComponentsView):
  1162. child_model = InterfaceTemplate
  1163. table = tables.InterfaceTemplateTable
  1164. filterset = filtersets.InterfaceTemplateFilterSet
  1165. viewname = 'dcim:devicetype_interfaces'
  1166. tab = ViewTab(
  1167. label=_('Interfaces'),
  1168. badge=lambda obj: obj.interface_template_count,
  1169. permission='dcim.view_interfacetemplate',
  1170. weight=520,
  1171. hide_if_empty=True
  1172. )
  1173. @register_model_view(DeviceType, 'frontports', path='front-ports')
  1174. class DeviceTypeFrontPortsView(DeviceTypeComponentsView):
  1175. child_model = FrontPortTemplate
  1176. table = tables.FrontPortTemplateTable
  1177. filterset = filtersets.FrontPortTemplateFilterSet
  1178. viewname = 'dcim:devicetype_frontports'
  1179. tab = ViewTab(
  1180. label=_('Front Ports'),
  1181. badge=lambda obj: obj.front_port_template_count,
  1182. permission='dcim.view_frontporttemplate',
  1183. weight=530,
  1184. hide_if_empty=True
  1185. )
  1186. @register_model_view(DeviceType, 'rearports', path='rear-ports')
  1187. class DeviceTypeRearPortsView(DeviceTypeComponentsView):
  1188. child_model = RearPortTemplate
  1189. table = tables.RearPortTemplateTable
  1190. filterset = filtersets.RearPortTemplateFilterSet
  1191. viewname = 'dcim:devicetype_rearports'
  1192. tab = ViewTab(
  1193. label=_('Rear Ports'),
  1194. badge=lambda obj: obj.rear_port_template_count,
  1195. permission='dcim.view_rearporttemplate',
  1196. weight=540,
  1197. hide_if_empty=True
  1198. )
  1199. @register_model_view(DeviceType, 'modulebays', path='module-bays')
  1200. class DeviceTypeModuleBaysView(DeviceTypeComponentsView):
  1201. child_model = ModuleBayTemplate
  1202. table = tables.ModuleBayTemplateTable
  1203. filterset = filtersets.ModuleBayTemplateFilterSet
  1204. viewname = 'dcim:devicetype_modulebays'
  1205. tab = ViewTab(
  1206. label=_('Module Bays'),
  1207. badge=lambda obj: obj.module_bay_template_count,
  1208. permission='dcim.view_modulebaytemplate',
  1209. weight=510,
  1210. hide_if_empty=True
  1211. )
  1212. @register_model_view(DeviceType, 'devicebays', path='device-bays')
  1213. class DeviceTypeDeviceBaysView(DeviceTypeComponentsView):
  1214. child_model = DeviceBayTemplate
  1215. table = tables.DeviceBayTemplateTable
  1216. filterset = filtersets.DeviceBayTemplateFilterSet
  1217. viewname = 'dcim:devicetype_devicebays'
  1218. tab = ViewTab(
  1219. label=_('Device Bays'),
  1220. badge=lambda obj: obj.device_bay_template_count,
  1221. permission='dcim.view_devicebaytemplate',
  1222. weight=500,
  1223. hide_if_empty=True
  1224. )
  1225. @register_model_view(DeviceType, 'inventoryitems', path='inventory-items')
  1226. class DeviceTypeInventoryItemsView(DeviceTypeComponentsView):
  1227. child_model = InventoryItemTemplate
  1228. table = tables.InventoryItemTemplateTable
  1229. filterset = filtersets.InventoryItemTemplateFilterSet
  1230. viewname = 'dcim:devicetype_inventoryitems'
  1231. tab = ViewTab(
  1232. label=_('Inventory Items'),
  1233. badge=lambda obj: obj.inventory_item_template_count,
  1234. permission='dcim.view_inventoryitemtemplate',
  1235. weight=590,
  1236. hide_if_empty=True
  1237. )
  1238. @register_model_view(DeviceType, 'bulk_import', path='import', detail=False)
  1239. class DeviceTypeImportView(generic.BulkImportView):
  1240. additional_permissions = [
  1241. 'dcim.add_devicetype',
  1242. 'dcim.add_consoleporttemplate',
  1243. 'dcim.add_consoleserverporttemplate',
  1244. 'dcim.add_powerporttemplate',
  1245. 'dcim.add_poweroutlettemplate',
  1246. 'dcim.add_interfacetemplate',
  1247. 'dcim.add_frontporttemplate',
  1248. 'dcim.add_rearporttemplate',
  1249. 'dcim.add_modulebaytemplate',
  1250. 'dcim.add_devicebaytemplate',
  1251. 'dcim.add_inventoryitemtemplate',
  1252. ]
  1253. queryset = DeviceType.objects.all()
  1254. model_form = forms.DeviceTypeImportForm
  1255. related_object_forms = {
  1256. 'console-ports': forms.ConsolePortTemplateImportForm,
  1257. 'console-server-ports': forms.ConsoleServerPortTemplateImportForm,
  1258. 'power-ports': forms.PowerPortTemplateImportForm,
  1259. 'power-outlets': forms.PowerOutletTemplateImportForm,
  1260. 'interfaces': forms.InterfaceTemplateImportForm,
  1261. 'rear-ports': forms.RearPortTemplateImportForm,
  1262. 'front-ports': forms.FrontPortTemplateImportForm,
  1263. 'port-mappings': forms.PortTemplateMappingImportForm,
  1264. 'module-bays': forms.ModuleBayTemplateImportForm,
  1265. 'device-bays': forms.DeviceBayTemplateImportForm,
  1266. 'inventory-items': forms.InventoryItemTemplateImportForm,
  1267. }
  1268. def prep_related_object_data(self, parent, data):
  1269. data.update({'device_type': parent})
  1270. return data
  1271. @register_model_view(DeviceType, 'bulk_edit', path='edit', detail=False)
  1272. class DeviceTypeBulkEditView(generic.BulkEditView):
  1273. queryset = DeviceType.objects.all()
  1274. filterset = filtersets.DeviceTypeFilterSet
  1275. table = tables.DeviceTypeTable
  1276. form = forms.DeviceTypeBulkEditForm
  1277. @register_model_view(DeviceType, 'bulk_rename', path='rename', detail=False)
  1278. class DeviceTypeBulkRenameView(generic.BulkRenameView):
  1279. queryset = DeviceType.objects.all()
  1280. field_name = 'model'
  1281. filterset = filtersets.DeviceTypeFilterSet
  1282. @register_model_view(DeviceType, 'bulk_delete', path='delete', detail=False)
  1283. class DeviceTypeBulkDeleteView(generic.BulkDeleteView):
  1284. queryset = DeviceType.objects.all()
  1285. filterset = filtersets.DeviceTypeFilterSet
  1286. table = tables.DeviceTypeTable
  1287. #
  1288. # Module type profiles
  1289. #
  1290. @register_model_view(ModuleTypeProfile, 'list', path='', detail=False)
  1291. class ModuleTypeProfileListView(generic.ObjectListView):
  1292. queryset = ModuleTypeProfile.objects.annotate(
  1293. instance_count=count_related(ModuleType, 'profile')
  1294. )
  1295. filterset = filtersets.ModuleTypeProfileFilterSet
  1296. filterset_form = forms.ModuleTypeProfileFilterForm
  1297. table = tables.ModuleTypeProfileTable
  1298. @register_model_view(ModuleTypeProfile)
  1299. class ModuleTypeProfileView(GetRelatedModelsMixin, generic.ObjectView):
  1300. template_name = 'generic/object.html'
  1301. queryset = ModuleTypeProfile.objects.all()
  1302. layout = layout.SimpleLayout(
  1303. left_panels=[
  1304. panels.ModuleTypeProfilePanel(),
  1305. TagsPanel(),
  1306. CommentsPanel(),
  1307. ],
  1308. right_panels=[
  1309. JSONPanel(field_name='schema', title=_('Schema')),
  1310. CustomFieldsPanel(),
  1311. ],
  1312. bottom_panels=[
  1313. ObjectsTablePanel(
  1314. model='dcim.ModuleType',
  1315. title=_('Module Types'),
  1316. filters={
  1317. 'profile_id': lambda ctx: ctx['object'].pk,
  1318. },
  1319. actions=[
  1320. actions.AddObject(
  1321. 'dcim.ModuleType',
  1322. url_params={
  1323. 'profile': lambda ctx: ctx['object'].pk,
  1324. }
  1325. ),
  1326. ],
  1327. ),
  1328. ]
  1329. )
  1330. @register_model_view(ModuleTypeProfile, 'add', detail=False)
  1331. @register_model_view(ModuleTypeProfile, 'edit')
  1332. class ModuleTypeProfileEditView(generic.ObjectEditView):
  1333. queryset = ModuleTypeProfile.objects.all()
  1334. form = forms.ModuleTypeProfileForm
  1335. @register_model_view(ModuleTypeProfile, 'delete')
  1336. class ModuleTypeProfileDeleteView(generic.ObjectDeleteView):
  1337. queryset = ModuleTypeProfile.objects.all()
  1338. @register_model_view(ModuleTypeProfile, 'bulk_import', detail=False)
  1339. class ModuleTypeProfileBulkImportView(generic.BulkImportView):
  1340. queryset = ModuleTypeProfile.objects.all()
  1341. model_form = forms.ModuleTypeProfileImportForm
  1342. @register_model_view(ModuleTypeProfile, 'bulk_edit', path='edit', detail=False)
  1343. class ModuleTypeProfileBulkEditView(generic.BulkEditView):
  1344. queryset = ModuleTypeProfile.objects.annotate(
  1345. instance_count=count_related(Module, 'module_type')
  1346. )
  1347. filterset = filtersets.ModuleTypeProfileFilterSet
  1348. table = tables.ModuleTypeProfileTable
  1349. form = forms.ModuleTypeProfileBulkEditForm
  1350. @register_model_view(ModuleTypeProfile, 'bulk_rename', path='rename', detail=False)
  1351. class ModuleTypeProfileBulkRenameView(generic.BulkRenameView):
  1352. queryset = ModuleTypeProfile.objects.all()
  1353. filterset = filtersets.ModuleTypeProfileFilterSet
  1354. @register_model_view(ModuleTypeProfile, 'bulk_delete', path='delete', detail=False)
  1355. class ModuleTypeProfileBulkDeleteView(generic.BulkDeleteView):
  1356. queryset = ModuleTypeProfile.objects.annotate(
  1357. instance_count=count_related(Module, 'module_type')
  1358. )
  1359. filterset = filtersets.ModuleTypeProfileFilterSet
  1360. table = tables.ModuleTypeProfileTable
  1361. #
  1362. # Module types
  1363. #
  1364. @register_model_view(ModuleType, 'list', path='', detail=False)
  1365. class ModuleTypeListView(generic.ObjectListView):
  1366. queryset = ModuleType.objects.all()
  1367. filterset = filtersets.ModuleTypeFilterSet
  1368. filterset_form = forms.ModuleTypeFilterForm
  1369. table = tables.ModuleTypeTable
  1370. @register_model_view(ModuleType)
  1371. class ModuleTypeView(GetRelatedModelsMixin, generic.ObjectView):
  1372. queryset = ModuleType.objects.all()
  1373. def get_extra_context(self, request, instance):
  1374. return {
  1375. 'related_models': self.get_related_models(request, instance, omit=[
  1376. ConsolePortTemplate, ConsoleServerPortTemplate, DeviceBayTemplate, FrontPortTemplate,
  1377. InventoryItemTemplate, InterfaceTemplate, ModuleBayTemplate, PowerOutletTemplate, PowerPortTemplate,
  1378. RearPortTemplate,
  1379. ]),
  1380. }
  1381. @register_model_view(ModuleType, 'add', detail=False)
  1382. @register_model_view(ModuleType, 'edit')
  1383. class ModuleTypeEditView(generic.ObjectEditView):
  1384. queryset = ModuleType.objects.all()
  1385. form = forms.ModuleTypeForm
  1386. @register_model_view(ModuleType, 'delete')
  1387. class ModuleTypeDeleteView(generic.ObjectDeleteView):
  1388. queryset = ModuleType.objects.all()
  1389. @register_model_view(ModuleType, 'consoleports', path='console-ports')
  1390. class ModuleTypeConsolePortsView(ModuleTypeComponentsView):
  1391. child_model = ConsolePortTemplate
  1392. table = tables.ConsolePortTemplateTable
  1393. filterset = filtersets.ConsolePortTemplateFilterSet
  1394. viewname = 'dcim:moduletype_consoleports'
  1395. tab = ViewTab(
  1396. label=_('Console Ports'),
  1397. badge=lambda obj: obj.consoleporttemplates.count(),
  1398. permission='dcim.view_consoleporttemplate',
  1399. weight=530,
  1400. hide_if_empty=True
  1401. )
  1402. @register_model_view(ModuleType, 'consoleserverports', path='console-server-ports')
  1403. class ModuleTypeConsoleServerPortsView(ModuleTypeComponentsView):
  1404. child_model = ConsoleServerPortTemplate
  1405. table = tables.ConsoleServerPortTemplateTable
  1406. filterset = filtersets.ConsoleServerPortTemplateFilterSet
  1407. viewname = 'dcim:moduletype_consoleserverports'
  1408. tab = ViewTab(
  1409. label=_('Console Server Ports'),
  1410. badge=lambda obj: obj.consoleserverporttemplates.count(),
  1411. permission='dcim.view_consoleserverporttemplate',
  1412. weight=540,
  1413. hide_if_empty=True
  1414. )
  1415. @register_model_view(ModuleType, 'powerports', path='power-ports')
  1416. class ModuleTypePowerPortsView(ModuleTypeComponentsView):
  1417. child_model = PowerPortTemplate
  1418. table = tables.PowerPortTemplateTable
  1419. filterset = filtersets.PowerPortTemplateFilterSet
  1420. viewname = 'dcim:moduletype_powerports'
  1421. tab = ViewTab(
  1422. label=_('Power Ports'),
  1423. badge=lambda obj: obj.powerporttemplates.count(),
  1424. permission='dcim.view_powerporttemplate',
  1425. weight=550,
  1426. hide_if_empty=True
  1427. )
  1428. @register_model_view(ModuleType, 'poweroutlets', path='power-outlets')
  1429. class ModuleTypePowerOutletsView(ModuleTypeComponentsView):
  1430. child_model = PowerOutletTemplate
  1431. table = tables.PowerOutletTemplateTable
  1432. filterset = filtersets.PowerOutletTemplateFilterSet
  1433. viewname = 'dcim:moduletype_poweroutlets'
  1434. tab = ViewTab(
  1435. label=_('Power Outlets'),
  1436. badge=lambda obj: obj.poweroutlettemplates.count(),
  1437. permission='dcim.view_poweroutlettemplate',
  1438. weight=560,
  1439. hide_if_empty=True
  1440. )
  1441. @register_model_view(ModuleType, 'interfaces')
  1442. class ModuleTypeInterfacesView(ModuleTypeComponentsView):
  1443. child_model = InterfaceTemplate
  1444. table = tables.InterfaceTemplateTable
  1445. filterset = filtersets.InterfaceTemplateFilterSet
  1446. viewname = 'dcim:moduletype_interfaces'
  1447. tab = ViewTab(
  1448. label=_('Interfaces'),
  1449. badge=lambda obj: obj.interfacetemplates.count(),
  1450. permission='dcim.view_interfacetemplate',
  1451. weight=500,
  1452. hide_if_empty=True
  1453. )
  1454. @register_model_view(ModuleType, 'frontports', path='front-ports')
  1455. class ModuleTypeFrontPortsView(ModuleTypeComponentsView):
  1456. child_model = FrontPortTemplate
  1457. table = tables.FrontPortTemplateTable
  1458. filterset = filtersets.FrontPortTemplateFilterSet
  1459. viewname = 'dcim:moduletype_frontports'
  1460. tab = ViewTab(
  1461. label=_('Front Ports'),
  1462. badge=lambda obj: obj.frontporttemplates.count(),
  1463. permission='dcim.view_frontporttemplate',
  1464. weight=510,
  1465. hide_if_empty=True
  1466. )
  1467. @register_model_view(ModuleType, 'rearports', path='rear-ports')
  1468. class ModuleTypeRearPortsView(ModuleTypeComponentsView):
  1469. child_model = RearPortTemplate
  1470. table = tables.RearPortTemplateTable
  1471. filterset = filtersets.RearPortTemplateFilterSet
  1472. viewname = 'dcim:moduletype_rearports'
  1473. tab = ViewTab(
  1474. label=_('Rear Ports'),
  1475. badge=lambda obj: obj.rearporttemplates.count(),
  1476. permission='dcim.view_rearporttemplate',
  1477. weight=520,
  1478. hide_if_empty=True
  1479. )
  1480. @register_model_view(ModuleType, 'modulebays', path='module-bays')
  1481. class ModuleTypeModuleBaysView(ModuleTypeComponentsView):
  1482. child_model = ModuleBayTemplate
  1483. table = tables.ModuleBayTemplateTable
  1484. filterset = filtersets.ModuleBayTemplateFilterSet
  1485. viewname = 'dcim:moduletype_modulebays'
  1486. tab = ViewTab(
  1487. label=_('Module Bays'),
  1488. badge=lambda obj: obj.modulebaytemplates.count(),
  1489. permission='dcim.view_modulebaytemplate',
  1490. weight=570,
  1491. hide_if_empty=True
  1492. )
  1493. @register_model_view(ModuleType, 'bulk_import', path='import', detail=False)
  1494. class ModuleTypeImportView(generic.BulkImportView):
  1495. additional_permissions = [
  1496. 'dcim.add_moduletype',
  1497. 'dcim.add_consoleporttemplate',
  1498. 'dcim.add_consoleserverporttemplate',
  1499. 'dcim.add_powerporttemplate',
  1500. 'dcim.add_poweroutlettemplate',
  1501. 'dcim.add_interfacetemplate',
  1502. 'dcim.add_frontporttemplate',
  1503. 'dcim.add_rearporttemplate',
  1504. 'dcim.add_modulebaytemplate',
  1505. ]
  1506. queryset = ModuleType.objects.all()
  1507. model_form = forms.ModuleTypeImportForm
  1508. related_object_forms = {
  1509. 'console-ports': forms.ConsolePortTemplateImportForm,
  1510. 'console-server-ports': forms.ConsoleServerPortTemplateImportForm,
  1511. 'power-ports': forms.PowerPortTemplateImportForm,
  1512. 'power-outlets': forms.PowerOutletTemplateImportForm,
  1513. 'interfaces': forms.InterfaceTemplateImportForm,
  1514. 'rear-ports': forms.RearPortTemplateImportForm,
  1515. 'front-ports': forms.FrontPortTemplateImportForm,
  1516. 'port-mappings': forms.PortTemplateMappingImportForm,
  1517. 'module-bays': forms.ModuleBayTemplateImportForm,
  1518. }
  1519. def prep_related_object_data(self, parent, data):
  1520. data.update({'module_type': parent})
  1521. return data
  1522. @register_model_view(ModuleType, 'bulk_edit', path='edit', detail=False)
  1523. class ModuleTypeBulkEditView(generic.BulkEditView):
  1524. queryset = ModuleType.objects.annotate(
  1525. instance_count=count_related(Module, 'module_type')
  1526. )
  1527. filterset = filtersets.ModuleTypeFilterSet
  1528. table = tables.ModuleTypeTable
  1529. form = forms.ModuleTypeBulkEditForm
  1530. @register_model_view(ModuleType, 'bulk_rename', path='rename', detail=False)
  1531. class ModuleTypeBulkRenameView(generic.BulkRenameView):
  1532. queryset = ModuleType.objects.all()
  1533. filterset = filtersets.ModuleTypeFilterSet
  1534. @register_model_view(ModuleType, 'bulk_delete', path='delete', detail=False)
  1535. class ModuleTypeBulkDeleteView(generic.BulkDeleteView):
  1536. queryset = ModuleType.objects.annotate(
  1537. instance_count=count_related(Module, 'module_type')
  1538. )
  1539. filterset = filtersets.ModuleTypeFilterSet
  1540. table = tables.ModuleTypeTable
  1541. #
  1542. # Console port templates
  1543. #
  1544. @register_model_view(ConsolePortTemplate, 'add', detail=False)
  1545. class ConsolePortTemplateCreateView(generic.ComponentCreateView):
  1546. queryset = ConsolePortTemplate.objects.all()
  1547. form = forms.ConsolePortTemplateCreateForm
  1548. model_form = forms.ConsolePortTemplateForm
  1549. @register_model_view(ConsolePortTemplate, 'edit')
  1550. class ConsolePortTemplateEditView(generic.ObjectEditView):
  1551. queryset = ConsolePortTemplate.objects.all()
  1552. form = forms.ConsolePortTemplateForm
  1553. @register_model_view(ConsolePortTemplate, 'delete')
  1554. class ConsolePortTemplateDeleteView(generic.ObjectDeleteView):
  1555. queryset = ConsolePortTemplate.objects.all()
  1556. @register_model_view(ConsolePortTemplate, 'bulk_edit', path='edit', detail=False)
  1557. class ConsolePortTemplateBulkEditView(generic.BulkEditView):
  1558. queryset = ConsolePortTemplate.objects.all()
  1559. table = tables.ConsolePortTemplateTable
  1560. form = forms.ConsolePortTemplateBulkEditForm
  1561. @register_model_view(ConsolePortTemplate, 'bulk_rename', path='rename', detail=False)
  1562. class ConsolePortTemplateBulkRenameView(generic.BulkRenameView):
  1563. queryset = ConsolePortTemplate.objects.all()
  1564. @register_model_view(ConsolePortTemplate, 'bulk_delete', path='delete', detail=False)
  1565. class ConsolePortTemplateBulkDeleteView(generic.BulkDeleteView):
  1566. queryset = ConsolePortTemplate.objects.all()
  1567. table = tables.ConsolePortTemplateTable
  1568. #
  1569. # Console server port templates
  1570. #
  1571. @register_model_view(ConsoleServerPortTemplate, 'add', detail=False)
  1572. class ConsoleServerPortTemplateCreateView(generic.ComponentCreateView):
  1573. queryset = ConsoleServerPortTemplate.objects.all()
  1574. form = forms.ConsoleServerPortTemplateCreateForm
  1575. model_form = forms.ConsoleServerPortTemplateForm
  1576. @register_model_view(ConsoleServerPortTemplate, 'edit')
  1577. class ConsoleServerPortTemplateEditView(generic.ObjectEditView):
  1578. queryset = ConsoleServerPortTemplate.objects.all()
  1579. form = forms.ConsoleServerPortTemplateForm
  1580. @register_model_view(ConsoleServerPortTemplate, 'delete')
  1581. class ConsoleServerPortTemplateDeleteView(generic.ObjectDeleteView):
  1582. queryset = ConsoleServerPortTemplate.objects.all()
  1583. @register_model_view(ConsoleServerPortTemplate, 'bulk_edit', path='edit', detail=False)
  1584. class ConsoleServerPortTemplateBulkEditView(generic.BulkEditView):
  1585. queryset = ConsoleServerPortTemplate.objects.all()
  1586. table = tables.ConsoleServerPortTemplateTable
  1587. form = forms.ConsoleServerPortTemplateBulkEditForm
  1588. @register_model_view(ConsoleServerPortTemplate, 'bulk_rename', detail=False)
  1589. class ConsoleServerPortTemplateBulkRenameView(generic.BulkRenameView):
  1590. queryset = ConsoleServerPortTemplate.objects.all()
  1591. @register_model_view(ConsoleServerPortTemplate, 'bulk_delete', path='delete', detail=False)
  1592. class ConsoleServerPortTemplateBulkDeleteView(generic.BulkDeleteView):
  1593. queryset = ConsoleServerPortTemplate.objects.all()
  1594. table = tables.ConsoleServerPortTemplateTable
  1595. #
  1596. # Power port templates
  1597. #
  1598. @register_model_view(PowerPortTemplate, 'add', detail=False)
  1599. class PowerPortTemplateCreateView(generic.ComponentCreateView):
  1600. queryset = PowerPortTemplate.objects.all()
  1601. form = forms.PowerPortTemplateCreateForm
  1602. model_form = forms.PowerPortTemplateForm
  1603. @register_model_view(PowerPortTemplate, 'edit')
  1604. class PowerPortTemplateEditView(generic.ObjectEditView):
  1605. queryset = PowerPortTemplate.objects.all()
  1606. form = forms.PowerPortTemplateForm
  1607. @register_model_view(PowerPortTemplate, 'delete')
  1608. class PowerPortTemplateDeleteView(generic.ObjectDeleteView):
  1609. queryset = PowerPortTemplate.objects.all()
  1610. @register_model_view(PowerPortTemplate, 'bulk_edit', path='edit', detail=False)
  1611. class PowerPortTemplateBulkEditView(generic.BulkEditView):
  1612. queryset = PowerPortTemplate.objects.all()
  1613. table = tables.PowerPortTemplateTable
  1614. form = forms.PowerPortTemplateBulkEditForm
  1615. @register_model_view(PowerPortTemplate, 'bulk_rename', path='rename', detail=False)
  1616. class PowerPortTemplateBulkRenameView(generic.BulkRenameView):
  1617. queryset = PowerPortTemplate.objects.all()
  1618. @register_model_view(PowerPortTemplate, 'bulk_delete', path='delete', detail=False)
  1619. class PowerPortTemplateBulkDeleteView(generic.BulkDeleteView):
  1620. queryset = PowerPortTemplate.objects.all()
  1621. table = tables.PowerPortTemplateTable
  1622. #
  1623. # Power outlet templates
  1624. #
  1625. @register_model_view(PowerOutletTemplate, 'add', detail=False)
  1626. class PowerOutletTemplateCreateView(generic.ComponentCreateView):
  1627. queryset = PowerOutletTemplate.objects.all()
  1628. form = forms.PowerOutletTemplateCreateForm
  1629. model_form = forms.PowerOutletTemplateForm
  1630. @register_model_view(PowerOutletTemplate, 'edit')
  1631. class PowerOutletTemplateEditView(generic.ObjectEditView):
  1632. queryset = PowerOutletTemplate.objects.all()
  1633. form = forms.PowerOutletTemplateForm
  1634. @register_model_view(PowerOutletTemplate, 'delete')
  1635. class PowerOutletTemplateDeleteView(generic.ObjectDeleteView):
  1636. queryset = PowerOutletTemplate.objects.all()
  1637. @register_model_view(PowerOutletTemplate, 'bulk_edit', path='edit', detail=False)
  1638. class PowerOutletTemplateBulkEditView(generic.BulkEditView):
  1639. queryset = PowerOutletTemplate.objects.all()
  1640. table = tables.PowerOutletTemplateTable
  1641. form = forms.PowerOutletTemplateBulkEditForm
  1642. @register_model_view(PowerOutletTemplate, 'bulk_rename', path='rename', detail=False)
  1643. class PowerOutletTemplateBulkRenameView(generic.BulkRenameView):
  1644. queryset = PowerOutletTemplate.objects.all()
  1645. @register_model_view(PowerOutletTemplate, 'bulk_delete', path='delete', detail=False)
  1646. class PowerOutletTemplateBulkDeleteView(generic.BulkDeleteView):
  1647. queryset = PowerOutletTemplate.objects.all()
  1648. table = tables.PowerOutletTemplateTable
  1649. #
  1650. # Interface templates
  1651. #
  1652. @register_model_view(InterfaceTemplate, 'add', detail=False)
  1653. class InterfaceTemplateCreateView(generic.ComponentCreateView):
  1654. queryset = InterfaceTemplate.objects.all()
  1655. form = forms.InterfaceTemplateCreateForm
  1656. model_form = forms.InterfaceTemplateForm
  1657. @register_model_view(InterfaceTemplate, 'edit')
  1658. class InterfaceTemplateEditView(generic.ObjectEditView):
  1659. queryset = InterfaceTemplate.objects.all()
  1660. form = forms.InterfaceTemplateForm
  1661. @register_model_view(InterfaceTemplate, 'delete')
  1662. class InterfaceTemplateDeleteView(generic.ObjectDeleteView):
  1663. queryset = InterfaceTemplate.objects.all()
  1664. @register_model_view(InterfaceTemplate, 'bulk_edit', path='edit', detail=False)
  1665. class InterfaceTemplateBulkEditView(generic.BulkEditView):
  1666. queryset = InterfaceTemplate.objects.all()
  1667. table = tables.InterfaceTemplateTable
  1668. form = forms.InterfaceTemplateBulkEditForm
  1669. @register_model_view(InterfaceTemplate, 'bulk_rename', path='rename', detail=False)
  1670. class InterfaceTemplateBulkRenameView(generic.BulkRenameView):
  1671. queryset = InterfaceTemplate.objects.all()
  1672. @register_model_view(InterfaceTemplate, 'bulk_delete', path='delete', detail=False)
  1673. class InterfaceTemplateBulkDeleteView(generic.BulkDeleteView):
  1674. queryset = InterfaceTemplate.objects.all()
  1675. table = tables.InterfaceTemplateTable
  1676. #
  1677. # Front port templates
  1678. #
  1679. @register_model_view(FrontPortTemplate, 'add', detail=False)
  1680. class FrontPortTemplateCreateView(generic.ComponentCreateView):
  1681. queryset = FrontPortTemplate.objects.all()
  1682. form = forms.FrontPortTemplateCreateForm
  1683. model_form = forms.FrontPortTemplateForm
  1684. @register_model_view(FrontPortTemplate, 'edit')
  1685. class FrontPortTemplateEditView(generic.ObjectEditView):
  1686. queryset = FrontPortTemplate.objects.all()
  1687. form = forms.FrontPortTemplateForm
  1688. @register_model_view(FrontPortTemplate, 'delete')
  1689. class FrontPortTemplateDeleteView(generic.ObjectDeleteView):
  1690. queryset = FrontPortTemplate.objects.all()
  1691. @register_model_view(FrontPortTemplate, 'bulk_edit', path='edit', detail=False)
  1692. class FrontPortTemplateBulkEditView(generic.BulkEditView):
  1693. queryset = FrontPortTemplate.objects.all()
  1694. table = tables.FrontPortTemplateTable
  1695. form = forms.FrontPortTemplateBulkEditForm
  1696. @register_model_view(FrontPortTemplate, 'bulk_rename', path='rename', detail=False)
  1697. class FrontPortTemplateBulkRenameView(generic.BulkRenameView):
  1698. queryset = FrontPortTemplate.objects.all()
  1699. @register_model_view(FrontPortTemplate, 'bulk_delete', path='delete', detail=False)
  1700. class FrontPortTemplateBulkDeleteView(generic.BulkDeleteView):
  1701. queryset = FrontPortTemplate.objects.all()
  1702. table = tables.FrontPortTemplateTable
  1703. #
  1704. # Rear port templates
  1705. #
  1706. @register_model_view(RearPortTemplate, 'add', detail=False)
  1707. class RearPortTemplateCreateView(generic.ComponentCreateView):
  1708. queryset = RearPortTemplate.objects.all()
  1709. form = forms.RearPortTemplateCreateForm
  1710. model_form = forms.RearPortTemplateForm
  1711. @register_model_view(RearPortTemplate, 'edit')
  1712. class RearPortTemplateEditView(generic.ObjectEditView):
  1713. queryset = RearPortTemplate.objects.all()
  1714. form = forms.RearPortTemplateForm
  1715. @register_model_view(RearPortTemplate, 'delete')
  1716. class RearPortTemplateDeleteView(generic.ObjectDeleteView):
  1717. queryset = RearPortTemplate.objects.all()
  1718. @register_model_view(RearPortTemplate, 'bulk_edit', path='edit', detail=False)
  1719. class RearPortTemplateBulkEditView(generic.BulkEditView):
  1720. queryset = RearPortTemplate.objects.all()
  1721. table = tables.RearPortTemplateTable
  1722. form = forms.RearPortTemplateBulkEditForm
  1723. @register_model_view(RearPortTemplate, 'bulk_rename', path='rename', detail=False)
  1724. class RearPortTemplateBulkRenameView(generic.BulkRenameView):
  1725. queryset = RearPortTemplate.objects.all()
  1726. @register_model_view(RearPortTemplate, 'bulk_delete', path='delete', detail=False)
  1727. class RearPortTemplateBulkDeleteView(generic.BulkDeleteView):
  1728. queryset = RearPortTemplate.objects.all()
  1729. table = tables.RearPortTemplateTable
  1730. #
  1731. # Module bay templates
  1732. #
  1733. @register_model_view(ModuleBayTemplate, 'add', detail=False)
  1734. class ModuleBayTemplateCreateView(generic.ComponentCreateView):
  1735. queryset = ModuleBayTemplate.objects.all()
  1736. form = forms.ModuleBayTemplateCreateForm
  1737. model_form = forms.ModuleBayTemplateForm
  1738. @register_model_view(ModuleBayTemplate, 'edit')
  1739. class ModuleBayTemplateEditView(generic.ObjectEditView):
  1740. queryset = ModuleBayTemplate.objects.all()
  1741. form = forms.ModuleBayTemplateForm
  1742. @register_model_view(ModuleBayTemplate, 'delete')
  1743. class ModuleBayTemplateDeleteView(generic.ObjectDeleteView):
  1744. queryset = ModuleBayTemplate.objects.all()
  1745. @register_model_view(ModuleBayTemplate, 'bulk_edit', path='edit', detail=False)
  1746. class ModuleBayTemplateBulkEditView(generic.BulkEditView):
  1747. queryset = ModuleBayTemplate.objects.all()
  1748. table = tables.ModuleBayTemplateTable
  1749. form = forms.ModuleBayTemplateBulkEditForm
  1750. @register_model_view(ModuleBayTemplate, 'bulk_rename', path='rename', detail=False)
  1751. class ModuleBayTemplateBulkRenameView(generic.BulkRenameView):
  1752. queryset = ModuleBayTemplate.objects.all()
  1753. @register_model_view(ModuleBayTemplate, 'bulk_delete', path='delete', detail=False)
  1754. class ModuleBayTemplateBulkDeleteView(generic.BulkDeleteView):
  1755. queryset = ModuleBayTemplate.objects.all()
  1756. table = tables.ModuleBayTemplateTable
  1757. #
  1758. # Device bay templates
  1759. #
  1760. @register_model_view(DeviceBayTemplate, 'add', detail=False)
  1761. class DeviceBayTemplateCreateView(generic.ComponentCreateView):
  1762. queryset = DeviceBayTemplate.objects.all()
  1763. form = forms.DeviceBayTemplateCreateForm
  1764. model_form = forms.DeviceBayTemplateForm
  1765. @register_model_view(DeviceBayTemplate, 'edit')
  1766. class DeviceBayTemplateEditView(generic.ObjectEditView):
  1767. queryset = DeviceBayTemplate.objects.all()
  1768. form = forms.DeviceBayTemplateForm
  1769. @register_model_view(DeviceBayTemplate, 'delete')
  1770. class DeviceBayTemplateDeleteView(generic.ObjectDeleteView):
  1771. queryset = DeviceBayTemplate.objects.all()
  1772. @register_model_view(DeviceBayTemplate, 'bulk_edit', path='edit', detail=False)
  1773. class DeviceBayTemplateBulkEditView(generic.BulkEditView):
  1774. queryset = DeviceBayTemplate.objects.all()
  1775. table = tables.DeviceBayTemplateTable
  1776. form = forms.DeviceBayTemplateBulkEditForm
  1777. @register_model_view(DeviceBayTemplate, 'bulk_rename', path='rename', detail=False)
  1778. class DeviceBayTemplateBulkRenameView(generic.BulkRenameView):
  1779. queryset = DeviceBayTemplate.objects.all()
  1780. @register_model_view(DeviceBayTemplate, 'bulk_delete', path='delete', detail=False)
  1781. class DeviceBayTemplateBulkDeleteView(generic.BulkDeleteView):
  1782. queryset = DeviceBayTemplate.objects.all()
  1783. table = tables.DeviceBayTemplateTable
  1784. #
  1785. # Inventory item templates
  1786. #
  1787. @register_model_view(InventoryItemTemplate, 'add', detail=False)
  1788. class InventoryItemTemplateCreateView(generic.ComponentCreateView):
  1789. queryset = InventoryItemTemplate.objects.all()
  1790. form = forms.InventoryItemTemplateCreateForm
  1791. model_form = forms.InventoryItemTemplateForm
  1792. def alter_object(self, instance, request):
  1793. # Set component (if any)
  1794. component_type = request.GET.get('component_type')
  1795. component_id = request.GET.get('component_id')
  1796. if component_type and component_id:
  1797. content_type = get_object_or_404(ContentType, pk=component_type)
  1798. instance.component = get_object_or_404(content_type.model_class(), pk=component_id)
  1799. return instance
  1800. @register_model_view(InventoryItemTemplate, 'edit')
  1801. class InventoryItemTemplateEditView(generic.ObjectEditView):
  1802. queryset = InventoryItemTemplate.objects.all()
  1803. form = forms.InventoryItemTemplateForm
  1804. @register_model_view(InventoryItemTemplate, 'delete')
  1805. class InventoryItemTemplateDeleteView(generic.ObjectDeleteView):
  1806. queryset = InventoryItemTemplate.objects.all()
  1807. @register_model_view(InventoryItemTemplate, 'bulk_edit', path='edit', detail=False)
  1808. class InventoryItemTemplateBulkEditView(generic.BulkEditView):
  1809. queryset = InventoryItemTemplate.objects.all()
  1810. table = tables.InventoryItemTemplateTable
  1811. form = forms.InventoryItemTemplateBulkEditForm
  1812. @register_model_view(InventoryItemTemplate, 'bulk_rename', path='rename', detail=False)
  1813. class InventoryItemTemplateBulkRenameView(generic.BulkRenameView):
  1814. queryset = InventoryItemTemplate.objects.all()
  1815. @register_model_view(InventoryItemTemplate, 'bulk_delete', path='delete', detail=False)
  1816. class InventoryItemTemplateBulkDeleteView(generic.BulkDeleteView):
  1817. queryset = InventoryItemTemplate.objects.all()
  1818. table = tables.InventoryItemTemplateTable
  1819. #
  1820. # Device roles
  1821. #
  1822. @register_model_view(DeviceRole, 'list', path='', detail=False)
  1823. class DeviceRoleListView(generic.ObjectListView):
  1824. queryset = DeviceRole.objects.add_related_count(
  1825. DeviceRole.objects.add_related_count(
  1826. DeviceRole.objects.all(),
  1827. VirtualMachine,
  1828. 'role',
  1829. 'vm_count',
  1830. cumulative=True
  1831. ),
  1832. Device,
  1833. 'role',
  1834. 'device_count',
  1835. cumulative=True
  1836. )
  1837. filterset = filtersets.DeviceRoleFilterSet
  1838. filterset_form = forms.DeviceRoleFilterForm
  1839. table = tables.DeviceRoleTable
  1840. @register_model_view(DeviceRole)
  1841. class DeviceRoleView(GetRelatedModelsMixin, generic.ObjectView):
  1842. queryset = DeviceRole.objects.all()
  1843. def get_extra_context(self, request, instance):
  1844. return {
  1845. 'related_models': self.get_related_models(request, instance),
  1846. }
  1847. @register_model_view(DeviceRole, 'add', detail=False)
  1848. @register_model_view(DeviceRole, 'edit')
  1849. class DeviceRoleEditView(generic.ObjectEditView):
  1850. queryset = DeviceRole.objects.all()
  1851. form = forms.DeviceRoleForm
  1852. @register_model_view(DeviceRole, 'delete')
  1853. class DeviceRoleDeleteView(generic.ObjectDeleteView):
  1854. queryset = DeviceRole.objects.all()
  1855. @register_model_view(DeviceRole, 'bulk_import', path='import', detail=False)
  1856. class DeviceRoleBulkImportView(generic.BulkImportView):
  1857. queryset = DeviceRole.objects.all()
  1858. model_form = forms.DeviceRoleImportForm
  1859. @register_model_view(DeviceRole, 'bulk_edit', path='edit', detail=False)
  1860. class DeviceRoleBulkEditView(generic.BulkEditView):
  1861. queryset = DeviceRole.objects.annotate(
  1862. device_count=count_related(Device, 'role'),
  1863. vm_count=count_related(VirtualMachine, 'role')
  1864. )
  1865. filterset = filtersets.DeviceRoleFilterSet
  1866. table = tables.DeviceRoleTable
  1867. form = forms.DeviceRoleBulkEditForm
  1868. @register_model_view(DeviceRole, 'bulk_rename', path='rename', detail=False)
  1869. class DeviceRoleBulkRenameView(generic.BulkRenameView):
  1870. queryset = DeviceRole.objects.all()
  1871. filterset = filtersets.DeviceRoleFilterSet
  1872. @register_model_view(DeviceRole, 'bulk_delete', path='delete', detail=False)
  1873. class DeviceRoleBulkDeleteView(generic.BulkDeleteView):
  1874. queryset = DeviceRole.objects.annotate(
  1875. device_count=count_related(Device, 'role'),
  1876. vm_count=count_related(VirtualMachine, 'role')
  1877. )
  1878. filterset = filtersets.DeviceRoleFilterSet
  1879. table = tables.DeviceRoleTable
  1880. #
  1881. # Platforms
  1882. #
  1883. @register_model_view(Platform, 'list', path='', detail=False)
  1884. class PlatformListView(generic.ObjectListView):
  1885. queryset = Platform.objects.add_related_count(
  1886. Platform.objects.add_related_count(
  1887. Platform.objects.all(),
  1888. VirtualMachine,
  1889. 'platform',
  1890. 'vm_count',
  1891. cumulative=True
  1892. ),
  1893. Device,
  1894. 'platform',
  1895. 'device_count',
  1896. cumulative=True
  1897. )
  1898. table = tables.PlatformTable
  1899. filterset = filtersets.PlatformFilterSet
  1900. filterset_form = forms.PlatformFilterForm
  1901. @register_model_view(Platform)
  1902. class PlatformView(GetRelatedModelsMixin, generic.ObjectView):
  1903. queryset = Platform.objects.all()
  1904. def get_extra_context(self, request, instance):
  1905. return {
  1906. 'related_models': self.get_related_models(request, instance),
  1907. }
  1908. @register_model_view(Platform, 'add', detail=False)
  1909. @register_model_view(Platform, 'edit')
  1910. class PlatformEditView(generic.ObjectEditView):
  1911. queryset = Platform.objects.all()
  1912. form = forms.PlatformForm
  1913. @register_model_view(Platform, 'delete')
  1914. class PlatformDeleteView(generic.ObjectDeleteView):
  1915. queryset = Platform.objects.all()
  1916. @register_model_view(Platform, 'bulk_import', path='import', detail=False)
  1917. class PlatformBulkImportView(generic.BulkImportView):
  1918. queryset = Platform.objects.all()
  1919. model_form = forms.PlatformImportForm
  1920. @register_model_view(Platform, 'bulk_edit', path='edit', detail=False)
  1921. class PlatformBulkEditView(generic.BulkEditView):
  1922. queryset = Platform.objects.all()
  1923. filterset = filtersets.PlatformFilterSet
  1924. table = tables.PlatformTable
  1925. form = forms.PlatformBulkEditForm
  1926. @register_model_view(Platform, 'bulk_rename', path='rename', detail=False)
  1927. class PlatformBulkRenameView(generic.BulkRenameView):
  1928. queryset = Platform.objects.all()
  1929. filterset = filtersets.PlatformFilterSet
  1930. @register_model_view(Platform, 'bulk_delete', path='delete', detail=False)
  1931. class PlatformBulkDeleteView(generic.BulkDeleteView):
  1932. queryset = Platform.objects.all()
  1933. filterset = filtersets.PlatformFilterSet
  1934. table = tables.PlatformTable
  1935. #
  1936. # Devices
  1937. #
  1938. @register_model_view(Device, 'list', path='', detail=False)
  1939. class DeviceListView(generic.ObjectListView):
  1940. queryset = Device.objects.select_related('virtual_chassis')
  1941. filterset = filtersets.DeviceFilterSet
  1942. filterset_form = forms.DeviceFilterForm
  1943. table = tables.DeviceTable
  1944. actions = (AddObject, BulkImport, BulkExport, BulkAddComponents, BulkEdit, BulkRename, BulkDelete)
  1945. @register_model_view(Device)
  1946. class DeviceView(generic.ObjectView):
  1947. queryset = Device.objects.all()
  1948. layout = layout.SimpleLayout(
  1949. left_panels=[
  1950. panels.DevicePanel(),
  1951. panels.VirtualChassisMembersPanel(),
  1952. CustomFieldsPanel(),
  1953. TagsPanel(),
  1954. CommentsPanel(),
  1955. ObjectsTablePanel(
  1956. model='dcim.VirtualDeviceContext',
  1957. filters={'device_id': lambda ctx: ctx['object'].pk},
  1958. actions=[
  1959. actions.AddObject('dcim.VirtualDeviceContext', url_params={'device': lambda ctx: ctx['object'].pk}),
  1960. ],
  1961. ),
  1962. ],
  1963. right_panels=[
  1964. panels.DeviceManagementPanel(),
  1965. panels.PowerUtilizationPanel(),
  1966. ObjectsTablePanel(
  1967. model='ipam.Service',
  1968. title=_('Application Services'),
  1969. filters={'device_id': lambda ctx: ctx['object'].pk},
  1970. actions=[
  1971. actions.AddObject(
  1972. 'ipam.Service',
  1973. url_params={
  1974. 'parent_object_type': lambda ctx: ContentType.objects.get_for_model(ctx['object']).pk,
  1975. 'parent': lambda ctx: ctx['object'].pk
  1976. }
  1977. ),
  1978. ],
  1979. ),
  1980. ImageAttachmentsPanel(),
  1981. panels.DeviceDimensionsPanel(),
  1982. TemplatePanel('dcim/panels/device_rack_elevations.html'),
  1983. ],
  1984. )
  1985. def get_extra_context(self, request, instance):
  1986. # VirtualChassis members
  1987. if instance.virtual_chassis is not None:
  1988. vc_members = Device.objects.restrict(request.user, 'view').filter(
  1989. virtual_chassis=instance.virtual_chassis
  1990. ).order_by('vc_position')
  1991. else:
  1992. vc_members = []
  1993. return {
  1994. 'vc_members': vc_members,
  1995. 'svg_extra': f'highlight=id:{instance.pk}',
  1996. }
  1997. @register_model_view(Device, 'add', detail=False)
  1998. @register_model_view(Device, 'edit')
  1999. class DeviceEditView(generic.ObjectEditView):
  2000. queryset = Device.objects.all()
  2001. form = forms.DeviceForm
  2002. template_name = 'dcim/device_edit.html'
  2003. @register_model_view(Device, 'delete')
  2004. class DeviceDeleteView(generic.ObjectDeleteView):
  2005. queryset = Device.objects.all()
  2006. @register_model_view(Device, 'consoleports', path='console-ports')
  2007. class DeviceConsolePortsView(DeviceComponentsView):
  2008. child_model = ConsolePort
  2009. table = tables.DeviceConsolePortTable
  2010. filterset = filtersets.ConsolePortFilterSet
  2011. filterset_form = forms.ConsolePortFilterForm
  2012. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDisconnect, BulkDelete)
  2013. tab = ViewTab(
  2014. label=_('Console Ports'),
  2015. badge=lambda obj: obj.console_port_count,
  2016. permission='dcim.view_consoleport',
  2017. weight=550,
  2018. hide_if_empty=True
  2019. )
  2020. @register_model_view(Device, 'consoleserverports', path='console-server-ports')
  2021. class DeviceConsoleServerPortsView(DeviceComponentsView):
  2022. child_model = ConsoleServerPort
  2023. table = tables.DeviceConsoleServerPortTable
  2024. filterset = filtersets.ConsoleServerPortFilterSet
  2025. filterset_form = forms.ConsoleServerPortFilterForm
  2026. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDisconnect, BulkDelete)
  2027. tab = ViewTab(
  2028. label=_('Console Server Ports'),
  2029. badge=lambda obj: obj.console_server_port_count,
  2030. permission='dcim.view_consoleserverport',
  2031. weight=560,
  2032. hide_if_empty=True
  2033. )
  2034. @register_model_view(Device, 'powerports', path='power-ports')
  2035. class DevicePowerPortsView(DeviceComponentsView):
  2036. child_model = PowerPort
  2037. table = tables.DevicePowerPortTable
  2038. filterset = filtersets.PowerPortFilterSet
  2039. filterset_form = forms.PowerPortFilterForm
  2040. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDisconnect, BulkDelete)
  2041. tab = ViewTab(
  2042. label=_('Power Ports'),
  2043. badge=lambda obj: obj.power_port_count,
  2044. permission='dcim.view_powerport',
  2045. weight=570,
  2046. hide_if_empty=True
  2047. )
  2048. @register_model_view(Device, 'poweroutlets', path='power-outlets')
  2049. class DevicePowerOutletsView(DeviceComponentsView):
  2050. child_model = PowerOutlet
  2051. table = tables.DevicePowerOutletTable
  2052. filterset = filtersets.PowerOutletFilterSet
  2053. filterset_form = forms.PowerOutletFilterForm
  2054. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDisconnect, BulkDelete)
  2055. tab = ViewTab(
  2056. label=_('Power Outlets'),
  2057. badge=lambda obj: obj.power_outlet_count,
  2058. permission='dcim.view_poweroutlet',
  2059. weight=580,
  2060. hide_if_empty=True
  2061. )
  2062. @register_model_view(Device, 'interfaces')
  2063. class DeviceInterfacesView(DeviceComponentsView):
  2064. child_model = Interface
  2065. table = tables.DeviceInterfaceTable
  2066. filterset = filtersets.InterfaceFilterSet
  2067. filterset_form = forms.InterfaceFilterForm
  2068. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDisconnect, BulkDelete)
  2069. template_name = 'dcim/device/interfaces.html'
  2070. tab = ViewTab(
  2071. label=_('Interfaces'),
  2072. badge=lambda obj: obj.vc_interfaces().count(),
  2073. permission='dcim.view_interface',
  2074. weight=520,
  2075. hide_if_empty=True
  2076. )
  2077. def get_children(self, request, parent):
  2078. return parent.vc_interfaces().restrict(request.user, 'view').prefetch_related(
  2079. Prefetch('ip_addresses', queryset=IPAddress.objects.restrict(request.user)),
  2080. Prefetch('member_interfaces', queryset=Interface.objects.restrict(request.user))
  2081. )
  2082. @register_model_view(Device, 'frontports', path='front-ports')
  2083. class DeviceFrontPortsView(DeviceComponentsView):
  2084. child_model = FrontPort
  2085. table = tables.DeviceFrontPortTable
  2086. filterset = filtersets.FrontPortFilterSet
  2087. filterset_form = forms.FrontPortFilterForm
  2088. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDisconnect, BulkDelete)
  2089. tab = ViewTab(
  2090. label=_('Front Ports'),
  2091. badge=lambda obj: obj.front_port_count,
  2092. permission='dcim.view_frontport',
  2093. weight=530,
  2094. hide_if_empty=True
  2095. )
  2096. @register_model_view(Device, 'rearports', path='rear-ports')
  2097. class DeviceRearPortsView(DeviceComponentsView):
  2098. child_model = RearPort
  2099. table = tables.DeviceRearPortTable
  2100. filterset = filtersets.RearPortFilterSet
  2101. filterset_form = forms.RearPortFilterForm
  2102. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDisconnect, BulkDelete)
  2103. tab = ViewTab(
  2104. label=_('Rear Ports'),
  2105. badge=lambda obj: obj.rear_port_count,
  2106. permission='dcim.view_rearport',
  2107. weight=540,
  2108. hide_if_empty=True
  2109. )
  2110. @register_model_view(Device, 'modulebays', path='module-bays')
  2111. class DeviceModuleBaysView(DeviceComponentsView):
  2112. child_model = ModuleBay
  2113. table = tables.DeviceModuleBayTable
  2114. filterset = filtersets.ModuleBayFilterSet
  2115. filterset_form = forms.ModuleBayFilterForm
  2116. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDelete)
  2117. tab = ViewTab(
  2118. label=_('Module Bays'),
  2119. badge=lambda obj: obj.module_bay_count,
  2120. permission='dcim.view_modulebay',
  2121. weight=510,
  2122. hide_if_empty=True
  2123. )
  2124. @register_model_view(Device, 'devicebays', path='device-bays')
  2125. class DeviceDeviceBaysView(DeviceComponentsView):
  2126. child_model = DeviceBay
  2127. table = tables.DeviceDeviceBayTable
  2128. filterset = filtersets.DeviceBayFilterSet
  2129. filterset_form = forms.DeviceBayFilterForm
  2130. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDelete)
  2131. tab = ViewTab(
  2132. label=_('Device Bays'),
  2133. badge=lambda obj: obj.device_bay_count,
  2134. permission='dcim.view_devicebay',
  2135. weight=500,
  2136. hide_if_empty=True
  2137. )
  2138. @register_model_view(Device, 'inventory')
  2139. class DeviceInventoryView(DeviceComponentsView):
  2140. child_model = InventoryItem
  2141. table = tables.DeviceInventoryItemTable
  2142. filterset = filtersets.InventoryItemFilterSet
  2143. filterset_form = forms.InventoryItemFilterForm
  2144. actions = (EditObject, DeleteObject, BulkEdit, BulkRename, BulkDelete)
  2145. tab = ViewTab(
  2146. label=_('Inventory Items'),
  2147. badge=lambda obj: obj.inventory_item_count,
  2148. permission='dcim.view_inventoryitem',
  2149. weight=590,
  2150. hide_if_empty=True
  2151. )
  2152. @register_model_view(Device, 'configcontext', path='config-context')
  2153. class DeviceConfigContextView(ObjectConfigContextView):
  2154. queryset = Device.objects.annotate_config_context_data()
  2155. base_template = 'dcim/device/base.html'
  2156. tab = ViewTab(
  2157. label=_('Config Context'),
  2158. weight=2000
  2159. )
  2160. @register_model_view(Device, 'render-config')
  2161. class DeviceRenderConfigView(ObjectRenderConfigView):
  2162. queryset = Device.objects.all()
  2163. base_template = 'dcim/device/base.html'
  2164. tab = ViewTab(
  2165. label=_('Render Config'),
  2166. weight=2100,
  2167. )
  2168. @register_model_view(Device, 'virtual-machines')
  2169. class DeviceVirtualMachinesView(generic.ObjectChildrenView):
  2170. queryset = Device.objects.all()
  2171. child_model = VirtualMachine
  2172. table = VirtualMachineTable
  2173. filterset = VirtualMachineFilterSet
  2174. filterset_form = VirtualMachineFilterForm
  2175. tab = ViewTab(
  2176. label=_('Virtual Machines'),
  2177. badge=lambda obj: VirtualMachine.objects.filter(cluster=obj.cluster, device=obj).count(),
  2178. weight=2200,
  2179. hide_if_empty=True,
  2180. permission='virtualization.view_virtualmachine'
  2181. )
  2182. def get_children(self, request, parent):
  2183. return self.child_model.objects.restrict(request.user, 'view').filter(cluster=parent.cluster, device=parent)
  2184. @register_model_view(Device, 'bulk_import', path='import', detail=False)
  2185. class DeviceBulkImportView(generic.BulkImportView):
  2186. queryset = Device.objects.all()
  2187. model_form = forms.DeviceImportForm
  2188. def save_object(self, object_form, request):
  2189. obj = object_form.save()
  2190. # For child devices, save the reverse relation to the parent device bay
  2191. if getattr(obj, 'parent_bay', None):
  2192. device_bay = obj.parent_bay
  2193. device_bay.installed_device = obj
  2194. device_bay.save()
  2195. return obj
  2196. @register_model_view(Device, 'bulk_edit', path='edit', detail=False)
  2197. class DeviceBulkEditView(generic.BulkEditView):
  2198. queryset = Device.objects.prefetch_related('device_type__manufacturer')
  2199. filterset = filtersets.DeviceFilterSet
  2200. table = tables.DeviceTable
  2201. form = forms.DeviceBulkEditForm
  2202. @register_model_view(Device, 'bulk_rename', path='rename', detail=False)
  2203. class DeviceBulkRenameView(generic.BulkRenameView):
  2204. queryset = Device.objects.all()
  2205. filterset = filtersets.DeviceFilterSet
  2206. table = tables.DeviceTable
  2207. @register_model_view(Device, 'bulk_delete', path='delete', detail=False)
  2208. class DeviceBulkDeleteView(generic.BulkDeleteView):
  2209. queryset = Device.objects.prefetch_related('device_type__manufacturer')
  2210. filterset = filtersets.DeviceFilterSet
  2211. table = tables.DeviceTable
  2212. #
  2213. # Modules
  2214. #
  2215. @register_model_view(Module, 'list', path='', detail=False)
  2216. class ModuleListView(generic.ObjectListView):
  2217. queryset = Module.objects.prefetch_related('module_type__manufacturer')
  2218. filterset = filtersets.ModuleFilterSet
  2219. filterset_form = forms.ModuleFilterForm
  2220. table = tables.ModuleTable
  2221. actions = (AddObject, BulkImport, BulkExport, BulkEdit, BulkDelete)
  2222. @register_model_view(Module)
  2223. class ModuleView(GetRelatedModelsMixin, generic.ObjectView):
  2224. queryset = Module.objects.all()
  2225. def get_extra_context(self, request, instance):
  2226. return {
  2227. 'related_models': self.get_related_models(request, instance),
  2228. }
  2229. @register_model_view(Module, 'add', detail=False)
  2230. @register_model_view(Module, 'edit')
  2231. class ModuleEditView(generic.ObjectEditView):
  2232. queryset = Module.objects.all()
  2233. form = forms.ModuleForm
  2234. @register_model_view(Module, 'delete')
  2235. class ModuleDeleteView(generic.ObjectDeleteView):
  2236. queryset = Module.objects.all()
  2237. @register_model_view(Module, 'bulk_import', path='import', detail=False)
  2238. class ModuleBulkImportView(generic.BulkImportView):
  2239. queryset = Module.objects.all()
  2240. model_form = forms.ModuleImportForm
  2241. @register_model_view(Module, 'bulk_edit', path='edit', detail=False)
  2242. class ModuleBulkEditView(generic.BulkEditView):
  2243. queryset = Module.objects.prefetch_related('module_type__manufacturer')
  2244. filterset = filtersets.ModuleFilterSet
  2245. table = tables.ModuleTable
  2246. form = forms.ModuleBulkEditForm
  2247. @register_model_view(Module, 'bulk_delete', path='delete', detail=False)
  2248. class ModuleBulkDeleteView(generic.BulkDeleteView):
  2249. queryset = Module.objects.prefetch_related('module_type__manufacturer')
  2250. filterset = filtersets.ModuleFilterSet
  2251. table = tables.ModuleTable
  2252. #
  2253. # Console ports
  2254. #
  2255. @register_model_view(ConsolePort, 'list', path='', detail=False)
  2256. class ConsolePortListView(generic.ObjectListView):
  2257. queryset = ConsolePort.objects.all()
  2258. filterset = filtersets.ConsolePortFilterSet
  2259. filterset_form = forms.ConsolePortFilterForm
  2260. table = tables.ConsolePortTable
  2261. @register_model_view(ConsolePort)
  2262. class ConsolePortView(generic.ObjectView):
  2263. queryset = ConsolePort.objects.all()
  2264. @register_model_view(ConsolePort, 'add', detail=False)
  2265. class ConsolePortCreateView(generic.ComponentCreateView):
  2266. queryset = ConsolePort.objects.all()
  2267. form = forms.ConsolePortCreateForm
  2268. model_form = forms.ConsolePortForm
  2269. @register_model_view(ConsolePort, 'edit')
  2270. class ConsolePortEditView(generic.ObjectEditView):
  2271. queryset = ConsolePort.objects.all()
  2272. form = forms.ConsolePortForm
  2273. @register_model_view(ConsolePort, 'delete')
  2274. class ConsolePortDeleteView(generic.ObjectDeleteView):
  2275. queryset = ConsolePort.objects.all()
  2276. @register_model_view(ConsolePort, 'bulk_import', path='import', detail=False)
  2277. class ConsolePortBulkImportView(generic.BulkImportView):
  2278. queryset = ConsolePort.objects.all()
  2279. model_form = forms.ConsolePortImportForm
  2280. @register_model_view(ConsolePort, 'bulk_edit', path='edit', detail=False)
  2281. class ConsolePortBulkEditView(generic.BulkEditView):
  2282. queryset = ConsolePort.objects.all()
  2283. filterset = filtersets.ConsolePortFilterSet
  2284. table = tables.ConsolePortTable
  2285. form = forms.ConsolePortBulkEditForm
  2286. @register_model_view(ConsolePort, 'bulk_rename', path='rename', detail=False)
  2287. class ConsolePortBulkRenameView(generic.BulkRenameView):
  2288. queryset = ConsolePort.objects.all()
  2289. filterset = filtersets.ConsolePortFilterSet
  2290. @register_model_view(ConsolePort, 'bulk_disconnect', path='disconnect', detail=False)
  2291. class ConsolePortBulkDisconnectView(BulkDisconnectView):
  2292. queryset = ConsolePort.objects.all()
  2293. @register_model_view(ConsolePort, 'bulk_delete', path='delete', detail=False)
  2294. class ConsolePortBulkDeleteView(generic.BulkDeleteView):
  2295. queryset = ConsolePort.objects.all()
  2296. filterset = filtersets.ConsolePortFilterSet
  2297. table = tables.ConsolePortTable
  2298. # Trace view
  2299. register_model_view(ConsolePort, 'trace', kwargs={'model': ConsolePort})(PathTraceView)
  2300. #
  2301. # Console server ports
  2302. #
  2303. @register_model_view(ConsoleServerPort, 'list', path='', detail=False)
  2304. class ConsoleServerPortListView(generic.ObjectListView):
  2305. queryset = ConsoleServerPort.objects.all()
  2306. filterset = filtersets.ConsoleServerPortFilterSet
  2307. filterset_form = forms.ConsoleServerPortFilterForm
  2308. table = tables.ConsoleServerPortTable
  2309. @register_model_view(ConsoleServerPort)
  2310. class ConsoleServerPortView(generic.ObjectView):
  2311. queryset = ConsoleServerPort.objects.all()
  2312. @register_model_view(ConsoleServerPort, 'add', detail=False)
  2313. class ConsoleServerPortCreateView(generic.ComponentCreateView):
  2314. queryset = ConsoleServerPort.objects.all()
  2315. form = forms.ConsoleServerPortCreateForm
  2316. model_form = forms.ConsoleServerPortForm
  2317. @register_model_view(ConsoleServerPort, 'edit')
  2318. class ConsoleServerPortEditView(generic.ObjectEditView):
  2319. queryset = ConsoleServerPort.objects.all()
  2320. form = forms.ConsoleServerPortForm
  2321. @register_model_view(ConsoleServerPort, 'delete')
  2322. class ConsoleServerPortDeleteView(generic.ObjectDeleteView):
  2323. queryset = ConsoleServerPort.objects.all()
  2324. @register_model_view(ConsoleServerPort, 'bulk_import', path='import', detail=False)
  2325. class ConsoleServerPortBulkImportView(generic.BulkImportView):
  2326. queryset = ConsoleServerPort.objects.all()
  2327. model_form = forms.ConsoleServerPortImportForm
  2328. @register_model_view(ConsoleServerPort, 'bulk_edit', path='edit', detail=False)
  2329. class ConsoleServerPortBulkEditView(generic.BulkEditView):
  2330. queryset = ConsoleServerPort.objects.all()
  2331. filterset = filtersets.ConsoleServerPortFilterSet
  2332. table = tables.ConsoleServerPortTable
  2333. form = forms.ConsoleServerPortBulkEditForm
  2334. @register_model_view(ConsoleServerPort, 'bulk_rename', path='rename', detail=False)
  2335. class ConsoleServerPortBulkRenameView(generic.BulkRenameView):
  2336. queryset = ConsoleServerPort.objects.all()
  2337. filterset = filtersets.ConsoleServerPortFilterSet
  2338. @register_model_view(ConsoleServerPort, 'bulk_disconnect', path='disconnect', detail=False)
  2339. class ConsoleServerPortBulkDisconnectView(BulkDisconnectView):
  2340. queryset = ConsoleServerPort.objects.all()
  2341. @register_model_view(ConsoleServerPort, 'bulk_delete', path='delete', detail=False)
  2342. class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView):
  2343. queryset = ConsoleServerPort.objects.all()
  2344. filterset = filtersets.ConsoleServerPortFilterSet
  2345. table = tables.ConsoleServerPortTable
  2346. # Trace view
  2347. register_model_view(ConsoleServerPort, 'trace', kwargs={'model': ConsoleServerPort})(PathTraceView)
  2348. #
  2349. # Power ports
  2350. #
  2351. @register_model_view(PowerPort, 'list', path='', detail=False)
  2352. class PowerPortListView(generic.ObjectListView):
  2353. queryset = PowerPort.objects.all()
  2354. filterset = filtersets.PowerPortFilterSet
  2355. filterset_form = forms.PowerPortFilterForm
  2356. table = tables.PowerPortTable
  2357. @register_model_view(PowerPort)
  2358. class PowerPortView(generic.ObjectView):
  2359. queryset = PowerPort.objects.all()
  2360. @register_model_view(PowerPort, 'add', detail=False)
  2361. class PowerPortCreateView(generic.ComponentCreateView):
  2362. queryset = PowerPort.objects.all()
  2363. form = forms.PowerPortCreateForm
  2364. model_form = forms.PowerPortForm
  2365. @register_model_view(PowerPort, 'edit')
  2366. class PowerPortEditView(generic.ObjectEditView):
  2367. queryset = PowerPort.objects.all()
  2368. form = forms.PowerPortForm
  2369. @register_model_view(PowerPort, 'delete')
  2370. class PowerPortDeleteView(generic.ObjectDeleteView):
  2371. queryset = PowerPort.objects.all()
  2372. @register_model_view(PowerPort, 'bulk_import', path='import', detail=False)
  2373. class PowerPortBulkImportView(generic.BulkImportView):
  2374. queryset = PowerPort.objects.all()
  2375. model_form = forms.PowerPortImportForm
  2376. @register_model_view(PowerPort, 'bulk_edit', path='edit', detail=False)
  2377. class PowerPortBulkEditView(generic.BulkEditView):
  2378. queryset = PowerPort.objects.all()
  2379. filterset = filtersets.PowerPortFilterSet
  2380. table = tables.PowerPortTable
  2381. form = forms.PowerPortBulkEditForm
  2382. @register_model_view(PowerPort, 'bulk_rename', path='rename', detail=False)
  2383. class PowerPortBulkRenameView(generic.BulkRenameView):
  2384. queryset = PowerPort.objects.all()
  2385. filterset = filtersets.PowerPortFilterSet
  2386. @register_model_view(PowerPort, 'bulk_disconnect', path='disconnect', detail=False)
  2387. class PowerPortBulkDisconnectView(BulkDisconnectView):
  2388. queryset = PowerPort.objects.all()
  2389. @register_model_view(PowerPort, 'bulk_delete', path='delete', detail=False)
  2390. class PowerPortBulkDeleteView(generic.BulkDeleteView):
  2391. queryset = PowerPort.objects.all()
  2392. filterset = filtersets.PowerPortFilterSet
  2393. table = tables.PowerPortTable
  2394. # Trace view
  2395. register_model_view(PowerPort, 'trace', kwargs={'model': PowerPort})(PathTraceView)
  2396. #
  2397. # Power outlets
  2398. #
  2399. @register_model_view(PowerOutlet, 'list', path='', detail=False)
  2400. class PowerOutletListView(generic.ObjectListView):
  2401. queryset = PowerOutlet.objects.all()
  2402. filterset = filtersets.PowerOutletFilterSet
  2403. filterset_form = forms.PowerOutletFilterForm
  2404. table = tables.PowerOutletTable
  2405. @register_model_view(PowerOutlet)
  2406. class PowerOutletView(generic.ObjectView):
  2407. queryset = PowerOutlet.objects.all()
  2408. @register_model_view(PowerOutlet, 'add', detail=False)
  2409. class PowerOutletCreateView(generic.ComponentCreateView):
  2410. queryset = PowerOutlet.objects.all()
  2411. form = forms.PowerOutletCreateForm
  2412. model_form = forms.PowerOutletForm
  2413. @register_model_view(PowerOutlet, 'edit')
  2414. class PowerOutletEditView(generic.ObjectEditView):
  2415. queryset = PowerOutlet.objects.all()
  2416. form = forms.PowerOutletForm
  2417. @register_model_view(PowerOutlet, 'delete')
  2418. class PowerOutletDeleteView(generic.ObjectDeleteView):
  2419. queryset = PowerOutlet.objects.all()
  2420. @register_model_view(PowerOutlet, 'bulk_import', path='import', detail=False)
  2421. class PowerOutletBulkImportView(generic.BulkImportView):
  2422. queryset = PowerOutlet.objects.all()
  2423. model_form = forms.PowerOutletImportForm
  2424. @register_model_view(PowerOutlet, 'bulk_edit', path='edit', detail=False)
  2425. class PowerOutletBulkEditView(generic.BulkEditView):
  2426. queryset = PowerOutlet.objects.all()
  2427. filterset = filtersets.PowerOutletFilterSet
  2428. table = tables.PowerOutletTable
  2429. form = forms.PowerOutletBulkEditForm
  2430. @register_model_view(PowerOutlet, 'bulk_rename', path='rename', detail=False)
  2431. class PowerOutletBulkRenameView(generic.BulkRenameView):
  2432. queryset = PowerOutlet.objects.all()
  2433. filterset = filtersets.PowerOutletFilterSet
  2434. @register_model_view(PowerOutlet, 'bulk_disconnect', path='disconnect', detail=False)
  2435. class PowerOutletBulkDisconnectView(BulkDisconnectView):
  2436. queryset = PowerOutlet.objects.all()
  2437. @register_model_view(PowerOutlet, 'bulk_delete', path='delete', detail=False)
  2438. class PowerOutletBulkDeleteView(generic.BulkDeleteView):
  2439. queryset = PowerOutlet.objects.all()
  2440. filterset = filtersets.PowerOutletFilterSet
  2441. table = tables.PowerOutletTable
  2442. # Trace view
  2443. register_model_view(PowerOutlet, 'trace', kwargs={'model': PowerOutlet})(PathTraceView)
  2444. #
  2445. # Interfaces
  2446. #
  2447. @register_model_view(Interface, 'list', path='', detail=False)
  2448. class InterfaceListView(generic.ObjectListView):
  2449. queryset = Interface.objects.all()
  2450. filterset = filtersets.InterfaceFilterSet
  2451. filterset_form = forms.InterfaceFilterForm
  2452. table = tables.InterfaceTable
  2453. @register_model_view(Interface)
  2454. class InterfaceView(generic.ObjectView):
  2455. queryset = Interface.objects.all()
  2456. def get_extra_context(self, request, instance):
  2457. # Get assigned VDCs
  2458. vdc_table = tables.VirtualDeviceContextTable(
  2459. data=instance.vdcs.restrict(request.user, 'view').prefetch_related('device'),
  2460. exclude=(
  2461. 'tenant', 'tenant_group', 'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'comments', 'tags',
  2462. 'created', 'last_updated', 'actions',
  2463. ),
  2464. orderable=False
  2465. )
  2466. vdc_table.configure(request)
  2467. # Get bridge interfaces
  2468. bridge_interfaces = Interface.objects.restrict(request.user, 'view').filter(bridge=instance)
  2469. bridge_interfaces_table = tables.InterfaceTable(
  2470. bridge_interfaces,
  2471. exclude=('device', 'parent'),
  2472. orderable=False
  2473. )
  2474. bridge_interfaces_table.configure(request)
  2475. # Get child interfaces
  2476. child_interfaces = Interface.objects.restrict(request.user, 'view').filter(parent=instance)
  2477. child_interfaces_table = tables.InterfaceTable(
  2478. child_interfaces,
  2479. exclude=('device', 'parent'),
  2480. orderable=False
  2481. )
  2482. child_interfaces_table.configure(request)
  2483. # Get assigned VLANs and annotate whether each is tagged or untagged
  2484. vlans = []
  2485. if instance.untagged_vlan is not None:
  2486. vlans.append(instance.untagged_vlan)
  2487. vlans[0].tagged = False
  2488. for vlan in instance.tagged_vlans.restrict(request.user).prefetch_related('site', 'group', 'tenant', 'role'):
  2489. vlan.tagged = True
  2490. vlans.append(vlan)
  2491. vlan_table = InterfaceVLANTable(
  2492. interface=instance,
  2493. data=vlans,
  2494. orderable=False
  2495. )
  2496. vlan_table.configure(request)
  2497. # Get VLAN translation rules
  2498. vlan_translation_table = None
  2499. if instance.vlan_translation_policy:
  2500. vlan_translation_table = VLANTranslationRuleTable(
  2501. data=instance.vlan_translation_policy.rules.all(),
  2502. orderable=False
  2503. )
  2504. vlan_translation_table.configure(request)
  2505. return {
  2506. 'vdc_table': vdc_table,
  2507. 'bridge_interfaces_table': bridge_interfaces_table,
  2508. 'child_interfaces_table': child_interfaces_table,
  2509. 'vlan_table': vlan_table,
  2510. 'vlan_translation_table': vlan_translation_table,
  2511. }
  2512. @register_model_view(Interface, 'add', detail=False)
  2513. class InterfaceCreateView(generic.ComponentCreateView):
  2514. queryset = Interface.objects.all()
  2515. form = forms.InterfaceCreateForm
  2516. model_form = forms.InterfaceForm
  2517. @register_model_view(Interface, 'edit')
  2518. class InterfaceEditView(generic.ObjectEditView):
  2519. queryset = Interface.objects.all()
  2520. form = forms.InterfaceForm
  2521. @register_model_view(Interface, 'delete')
  2522. class InterfaceDeleteView(generic.ObjectDeleteView):
  2523. queryset = Interface.objects.all()
  2524. @register_model_view(Interface, 'bulk_import', path='import', detail=False)
  2525. class InterfaceBulkImportView(generic.BulkImportView):
  2526. queryset = Interface.objects.all()
  2527. model_form = forms.InterfaceImportForm
  2528. @register_model_view(Interface, 'bulk_edit', path='edit', detail=False)
  2529. class InterfaceBulkEditView(generic.BulkEditView):
  2530. queryset = Interface.objects.all()
  2531. filterset = filtersets.InterfaceFilterSet
  2532. table = tables.InterfaceTable
  2533. form = forms.InterfaceBulkEditForm
  2534. def post_save_operations(self, form, obj):
  2535. super().post_save_operations(form, obj)
  2536. # Add/remove tagged VLANs
  2537. if obj.mode == InterfaceModeChoices.MODE_TAGGED:
  2538. if form.cleaned_data.get('add_tagged_vlans', None):
  2539. obj.tagged_vlans.add(*form.cleaned_data['add_tagged_vlans'])
  2540. if form.cleaned_data.get('remove_tagged_vlans', None):
  2541. obj.tagged_vlans.remove(*form.cleaned_data['remove_tagged_vlans'])
  2542. @register_model_view(Interface, 'bulk_rename', path='rename', detail=False)
  2543. class InterfaceBulkRenameView(generic.BulkRenameView):
  2544. queryset = Interface.objects.all()
  2545. filterset = filtersets.InterfaceFilterSet
  2546. @register_model_view(Interface, 'bulk_disconnect', path='disconnect', detail=False)
  2547. class InterfaceBulkDisconnectView(BulkDisconnectView):
  2548. queryset = Interface.objects.all()
  2549. @register_model_view(Interface, 'bulk_delete', path='delete', detail=False)
  2550. class InterfaceBulkDeleteView(generic.BulkDeleteView):
  2551. # Ensure child interfaces are deleted prior to their parents
  2552. queryset = Interface.objects.order_by('device', 'parent', CollateAsChar('_name'))
  2553. filterset = filtersets.InterfaceFilterSet
  2554. table = tables.InterfaceTable
  2555. # Trace view
  2556. register_model_view(Interface, 'trace', kwargs={'model': Interface})(PathTraceView)
  2557. #
  2558. # Front ports
  2559. #
  2560. @register_model_view(FrontPort, 'list', path='', detail=False)
  2561. class FrontPortListView(generic.ObjectListView):
  2562. queryset = FrontPort.objects.all()
  2563. filterset = filtersets.FrontPortFilterSet
  2564. filterset_form = forms.FrontPortFilterForm
  2565. table = tables.FrontPortTable
  2566. @register_model_view(FrontPort)
  2567. class FrontPortView(generic.ObjectView):
  2568. queryset = FrontPort.objects.all()
  2569. def get_extra_context(self, request, instance):
  2570. return {
  2571. 'rear_port_mappings': PortMapping.objects.filter(front_port=instance).prefetch_related('rear_port'),
  2572. }
  2573. @register_model_view(FrontPort, 'add', detail=False)
  2574. class FrontPortCreateView(generic.ComponentCreateView):
  2575. queryset = FrontPort.objects.all()
  2576. form = forms.FrontPortCreateForm
  2577. model_form = forms.FrontPortForm
  2578. @register_model_view(FrontPort, 'edit')
  2579. class FrontPortEditView(generic.ObjectEditView):
  2580. queryset = FrontPort.objects.all()
  2581. form = forms.FrontPortForm
  2582. @register_model_view(FrontPort, 'delete')
  2583. class FrontPortDeleteView(generic.ObjectDeleteView):
  2584. queryset = FrontPort.objects.all()
  2585. @register_model_view(FrontPort, 'bulk_import', path='import', detail=False)
  2586. class FrontPortBulkImportView(generic.BulkImportView):
  2587. queryset = FrontPort.objects.all()
  2588. model_form = forms.FrontPortImportForm
  2589. @register_model_view(FrontPort, 'bulk_edit', path='edit', detail=False)
  2590. class FrontPortBulkEditView(generic.BulkEditView):
  2591. queryset = FrontPort.objects.all()
  2592. filterset = filtersets.FrontPortFilterSet
  2593. table = tables.FrontPortTable
  2594. form = forms.FrontPortBulkEditForm
  2595. @register_model_view(FrontPort, 'bulk_rename', path='rename', detail=False)
  2596. class FrontPortBulkRenameView(generic.BulkRenameView):
  2597. queryset = FrontPort.objects.all()
  2598. filterset = filtersets.FrontPortFilterSet
  2599. @register_model_view(FrontPort, 'bulk_disconnect', path='disconnect', detail=False)
  2600. class FrontPortBulkDisconnectView(BulkDisconnectView):
  2601. queryset = FrontPort.objects.all()
  2602. @register_model_view(FrontPort, 'bulk_delete', path='delete', detail=False)
  2603. class FrontPortBulkDeleteView(generic.BulkDeleteView):
  2604. queryset = FrontPort.objects.all()
  2605. filterset = filtersets.FrontPortFilterSet
  2606. table = tables.FrontPortTable
  2607. # Trace view
  2608. register_model_view(FrontPort, 'trace', kwargs={'model': FrontPort})(PathTraceView)
  2609. #
  2610. # Rear ports
  2611. #
  2612. @register_model_view(RearPort, 'list', path='', detail=False)
  2613. class RearPortListView(generic.ObjectListView):
  2614. queryset = RearPort.objects.all()
  2615. filterset = filtersets.RearPortFilterSet
  2616. filterset_form = forms.RearPortFilterForm
  2617. table = tables.RearPortTable
  2618. @register_model_view(RearPort)
  2619. class RearPortView(generic.ObjectView):
  2620. queryset = RearPort.objects.all()
  2621. def get_extra_context(self, request, instance):
  2622. return {
  2623. 'front_port_mappings': PortMapping.objects.filter(rear_port=instance).prefetch_related('front_port'),
  2624. }
  2625. @register_model_view(RearPort, 'add', detail=False)
  2626. class RearPortCreateView(generic.ComponentCreateView):
  2627. queryset = RearPort.objects.all()
  2628. form = forms.RearPortCreateForm
  2629. model_form = forms.RearPortForm
  2630. @register_model_view(RearPort, 'edit')
  2631. class RearPortEditView(generic.ObjectEditView):
  2632. queryset = RearPort.objects.all()
  2633. form = forms.RearPortForm
  2634. @register_model_view(RearPort, 'delete')
  2635. class RearPortDeleteView(generic.ObjectDeleteView):
  2636. queryset = RearPort.objects.all()
  2637. @register_model_view(RearPort, 'bulk_import', path='import', detail=False)
  2638. class RearPortBulkImportView(generic.BulkImportView):
  2639. queryset = RearPort.objects.all()
  2640. model_form = forms.RearPortImportForm
  2641. @register_model_view(RearPort, 'bulk_edit', path='edit', detail=False)
  2642. class RearPortBulkEditView(generic.BulkEditView):
  2643. queryset = RearPort.objects.all()
  2644. filterset = filtersets.RearPortFilterSet
  2645. table = tables.RearPortTable
  2646. form = forms.RearPortBulkEditForm
  2647. @register_model_view(RearPort, 'bulk_rename', path='rename', detail=False)
  2648. class RearPortBulkRenameView(generic.BulkRenameView):
  2649. queryset = RearPort.objects.all()
  2650. @register_model_view(RearPort, 'bulk_disconnect', path='disconnect', detail=False)
  2651. class RearPortBulkDisconnectView(BulkDisconnectView):
  2652. queryset = RearPort.objects.all()
  2653. filterset = filtersets.RearPortFilterSet
  2654. @register_model_view(RearPort, 'bulk_delete', path='delete', detail=False)
  2655. class RearPortBulkDeleteView(generic.BulkDeleteView):
  2656. queryset = RearPort.objects.all()
  2657. filterset = filtersets.RearPortFilterSet
  2658. table = tables.RearPortTable
  2659. # Trace view
  2660. register_model_view(RearPort, 'trace', kwargs={'model': RearPort})(PathTraceView)
  2661. #
  2662. # Module bays
  2663. #
  2664. @register_model_view(ModuleBay, 'list', path='', detail=False)
  2665. class ModuleBayListView(generic.ObjectListView):
  2666. queryset = ModuleBay.objects.select_related('installed_module__module_type')
  2667. filterset = filtersets.ModuleBayFilterSet
  2668. filterset_form = forms.ModuleBayFilterForm
  2669. table = tables.ModuleBayTable
  2670. @register_model_view(ModuleBay)
  2671. class ModuleBayView(generic.ObjectView):
  2672. queryset = ModuleBay.objects.all()
  2673. @register_model_view(ModuleBay, 'add', detail=False)
  2674. class ModuleBayCreateView(generic.ComponentCreateView):
  2675. queryset = ModuleBay.objects.all()
  2676. form = forms.ModuleBayCreateForm
  2677. model_form = forms.ModuleBayForm
  2678. @register_model_view(ModuleBay, 'edit')
  2679. class ModuleBayEditView(generic.ObjectEditView):
  2680. queryset = ModuleBay.objects.all()
  2681. form = forms.ModuleBayForm
  2682. @register_model_view(ModuleBay, 'delete')
  2683. class ModuleBayDeleteView(generic.ObjectDeleteView):
  2684. queryset = ModuleBay.objects.all()
  2685. @register_model_view(ModuleBay, 'bulk_import', path='import', detail=False)
  2686. class ModuleBayBulkImportView(generic.BulkImportView):
  2687. queryset = ModuleBay.objects.all()
  2688. model_form = forms.ModuleBayImportForm
  2689. @register_model_view(ModuleBay, 'bulk_edit', path='edit', detail=False)
  2690. class ModuleBayBulkEditView(generic.BulkEditView):
  2691. queryset = ModuleBay.objects.all()
  2692. filterset = filtersets.ModuleBayFilterSet
  2693. table = tables.ModuleBayTable
  2694. form = forms.ModuleBayBulkEditForm
  2695. @register_model_view(ModuleBay, 'bulk_rename', path='rename', detail=False)
  2696. class ModuleBayBulkRenameView(generic.BulkRenameView):
  2697. queryset = ModuleBay.objects.all()
  2698. filterset = filtersets.ModuleBayFilterSet
  2699. @register_model_view(ModuleBay, 'bulk_delete', path='delete', detail=False)
  2700. class ModuleBayBulkDeleteView(generic.BulkDeleteView):
  2701. queryset = ModuleBay.objects.all()
  2702. filterset = filtersets.ModuleBayFilterSet
  2703. table = tables.ModuleBayTable
  2704. #
  2705. # Device bays
  2706. #
  2707. @register_model_view(DeviceBay, 'list', path='', detail=False)
  2708. class DeviceBayListView(generic.ObjectListView):
  2709. queryset = DeviceBay.objects.all()
  2710. filterset = filtersets.DeviceBayFilterSet
  2711. filterset_form = forms.DeviceBayFilterForm
  2712. table = tables.DeviceBayTable
  2713. @register_model_view(DeviceBay)
  2714. class DeviceBayView(generic.ObjectView):
  2715. queryset = DeviceBay.objects.all()
  2716. @register_model_view(DeviceBay, 'add', detail=False)
  2717. class DeviceBayCreateView(generic.ComponentCreateView):
  2718. queryset = DeviceBay.objects.all()
  2719. form = forms.DeviceBayCreateForm
  2720. model_form = forms.DeviceBayForm
  2721. @register_model_view(DeviceBay, 'edit')
  2722. class DeviceBayEditView(generic.ObjectEditView):
  2723. queryset = DeviceBay.objects.all()
  2724. form = forms.DeviceBayForm
  2725. @register_model_view(DeviceBay, 'delete')
  2726. class DeviceBayDeleteView(generic.ObjectDeleteView):
  2727. queryset = DeviceBay.objects.all()
  2728. @register_model_view(DeviceBay, 'populate')
  2729. class DeviceBayPopulateView(generic.ObjectEditView):
  2730. queryset = DeviceBay.objects.all()
  2731. def get(self, request, pk):
  2732. device_bay = get_object_or_404(self.queryset, pk=pk)
  2733. form = forms.PopulateDeviceBayForm(device_bay)
  2734. return render(request, 'dcim/devicebay_populate.html', {
  2735. 'device_bay': device_bay,
  2736. 'form': form,
  2737. 'return_url': self.get_return_url(request, device_bay),
  2738. })
  2739. def post(self, request, pk):
  2740. device_bay = get_object_or_404(self.queryset, pk=pk)
  2741. form = forms.PopulateDeviceBayForm(device_bay, request.POST)
  2742. if form.is_valid():
  2743. device_bay.snapshot()
  2744. device_bay.installed_device = form.cleaned_data['installed_device']
  2745. device_bay.save()
  2746. messages.success(
  2747. request,
  2748. _("Installed device {device} in bay {device_bay}.").format(
  2749. device=device_bay.installed_device,
  2750. device_bay=device_bay
  2751. )
  2752. )
  2753. return_url = self.get_return_url(request)
  2754. return redirect(return_url)
  2755. return render(request, 'dcim/devicebay_populate.html', {
  2756. 'device_bay': device_bay,
  2757. 'form': form,
  2758. 'return_url': self.get_return_url(request, device_bay),
  2759. })
  2760. @register_model_view(DeviceBay, 'depopulate')
  2761. class DeviceBayDepopulateView(generic.ObjectEditView):
  2762. queryset = DeviceBay.objects.all()
  2763. def get(self, request, pk):
  2764. device_bay = get_object_or_404(self.queryset, pk=pk)
  2765. form = ConfirmationForm()
  2766. return render(request, 'dcim/devicebay_depopulate.html', {
  2767. 'device_bay': device_bay,
  2768. 'form': form,
  2769. 'return_url': self.get_return_url(request, device_bay),
  2770. })
  2771. def post(self, request, pk):
  2772. device_bay = get_object_or_404(self.queryset, pk=pk)
  2773. form = ConfirmationForm(request.POST)
  2774. if form.is_valid():
  2775. device_bay.snapshot()
  2776. removed_device = device_bay.installed_device
  2777. device_bay.installed_device = None
  2778. device_bay.save()
  2779. messages.success(
  2780. request,
  2781. _("Removed device {device} from bay {device_bay}.").format(
  2782. device=removed_device,
  2783. device_bay=device_bay
  2784. )
  2785. )
  2786. return_url = self.get_return_url(request, device_bay.device)
  2787. return redirect(return_url)
  2788. return render(request, 'dcim/devicebay_depopulate.html', {
  2789. 'device_bay': device_bay,
  2790. 'form': form,
  2791. 'return_url': self.get_return_url(request, device_bay),
  2792. })
  2793. @register_model_view(DeviceBay, 'bulk_import', path='import', detail=False)
  2794. class DeviceBayBulkImportView(generic.BulkImportView):
  2795. queryset = DeviceBay.objects.all()
  2796. model_form = forms.DeviceBayImportForm
  2797. @register_model_view(DeviceBay, 'bulk_edit', path='edit', detail=False)
  2798. class DeviceBayBulkEditView(generic.BulkEditView):
  2799. queryset = DeviceBay.objects.all()
  2800. filterset = filtersets.DeviceBayFilterSet
  2801. table = tables.DeviceBayTable
  2802. form = forms.DeviceBayBulkEditForm
  2803. @register_model_view(DeviceBay, 'bulk_rename', path='rename', detail=False)
  2804. class DeviceBayBulkRenameView(generic.BulkRenameView):
  2805. queryset = DeviceBay.objects.all()
  2806. filterset = filtersets.DeviceBayFilterSet
  2807. @register_model_view(DeviceBay, 'bulk_delete', path='delete', detail=False)
  2808. class DeviceBayBulkDeleteView(generic.BulkDeleteView):
  2809. queryset = DeviceBay.objects.all()
  2810. filterset = filtersets.DeviceBayFilterSet
  2811. table = tables.DeviceBayTable
  2812. #
  2813. # Inventory items
  2814. #
  2815. @register_model_view(InventoryItem, 'list', path='', detail=False)
  2816. class InventoryItemListView(generic.ObjectListView):
  2817. queryset = InventoryItem.objects.all()
  2818. filterset = filtersets.InventoryItemFilterSet
  2819. filterset_form = forms.InventoryItemFilterForm
  2820. table = tables.InventoryItemTable
  2821. @register_model_view(InventoryItem)
  2822. class InventoryItemView(generic.ObjectView):
  2823. queryset = InventoryItem.objects.all()
  2824. @register_model_view(InventoryItem, 'edit')
  2825. class InventoryItemEditView(generic.ObjectEditView):
  2826. queryset = InventoryItem.objects.all()
  2827. form = forms.InventoryItemForm
  2828. @register_model_view(InventoryItem, 'add', detail=False)
  2829. class InventoryItemCreateView(generic.ComponentCreateView):
  2830. queryset = InventoryItem.objects.all()
  2831. form = forms.InventoryItemCreateForm
  2832. model_form = forms.InventoryItemForm
  2833. @register_model_view(InventoryItem, 'delete')
  2834. class InventoryItemDeleteView(generic.ObjectDeleteView):
  2835. queryset = InventoryItem.objects.all()
  2836. @register_model_view(InventoryItem, 'bulk_import', path='import', detail=False)
  2837. class InventoryItemBulkImportView(generic.BulkImportView):
  2838. queryset = InventoryItem.objects.all()
  2839. model_form = forms.InventoryItemImportForm
  2840. @register_model_view(InventoryItem, 'bulk_edit', path='edit', detail=False)
  2841. class InventoryItemBulkEditView(generic.BulkEditView):
  2842. queryset = InventoryItem.objects.all()
  2843. filterset = filtersets.InventoryItemFilterSet
  2844. table = tables.InventoryItemTable
  2845. form = forms.InventoryItemBulkEditForm
  2846. @register_model_view(InventoryItem, 'bulk_rename', path='rename', detail=False)
  2847. class InventoryItemBulkRenameView(generic.BulkRenameView):
  2848. queryset = InventoryItem.objects.all()
  2849. filterset = filtersets.InventoryItemFilterSet
  2850. @register_model_view(InventoryItem, 'bulk_delete', path='delete', detail=False)
  2851. class InventoryItemBulkDeleteView(generic.BulkDeleteView):
  2852. queryset = InventoryItem.objects.all()
  2853. filterset = filtersets.InventoryItemFilterSet
  2854. table = tables.InventoryItemTable
  2855. @register_model_view(InventoryItem, 'children')
  2856. class InventoryItemChildrenView(generic.ObjectChildrenView):
  2857. queryset = InventoryItem.objects.all()
  2858. child_model = InventoryItem
  2859. table = tables.InventoryItemTable
  2860. filterset = filtersets.InventoryItemFilterSet
  2861. filterset_form = forms.InventoryItemFilterForm
  2862. tab = ViewTab(
  2863. label=_('Children'),
  2864. badge=lambda obj: obj.child_items.count(),
  2865. permission='dcim.view_inventoryitem',
  2866. hide_if_empty=True,
  2867. weight=5000
  2868. )
  2869. def get_children(self, request, parent):
  2870. return parent.child_items.restrict(request.user, 'view')
  2871. #
  2872. # Inventory item roles
  2873. #
  2874. @register_model_view(InventoryItemRole, 'list', path='', detail=False)
  2875. class InventoryItemRoleListView(generic.ObjectListView):
  2876. queryset = InventoryItemRole.objects.annotate(
  2877. inventoryitem_count=count_related(InventoryItem, 'role'),
  2878. )
  2879. filterset = filtersets.InventoryItemRoleFilterSet
  2880. filterset_form = forms.InventoryItemRoleFilterForm
  2881. table = tables.InventoryItemRoleTable
  2882. @register_model_view(InventoryItemRole)
  2883. class InventoryItemRoleView(generic.ObjectView):
  2884. queryset = InventoryItemRole.objects.all()
  2885. def get_extra_context(self, request, instance):
  2886. return {
  2887. 'inventoryitem_count': InventoryItem.objects.filter(role=instance).count(),
  2888. }
  2889. @register_model_view(InventoryItemRole, 'add', detail=False)
  2890. @register_model_view(InventoryItemRole, 'edit')
  2891. class InventoryItemRoleEditView(generic.ObjectEditView):
  2892. queryset = InventoryItemRole.objects.all()
  2893. form = forms.InventoryItemRoleForm
  2894. @register_model_view(InventoryItemRole, 'delete')
  2895. class InventoryItemRoleDeleteView(generic.ObjectDeleteView):
  2896. queryset = InventoryItemRole.objects.all()
  2897. @register_model_view(InventoryItemRole, 'bulk_import', path='import', detail=False)
  2898. class InventoryItemRoleBulkImportView(generic.BulkImportView):
  2899. queryset = InventoryItemRole.objects.all()
  2900. model_form = forms.InventoryItemRoleImportForm
  2901. @register_model_view(InventoryItemRole, 'bulk_edit', path='edit', detail=False)
  2902. class InventoryItemRoleBulkEditView(generic.BulkEditView):
  2903. queryset = InventoryItemRole.objects.annotate(
  2904. inventoryitem_count=count_related(InventoryItem, 'role'),
  2905. )
  2906. filterset = filtersets.InventoryItemRoleFilterSet
  2907. table = tables.InventoryItemRoleTable
  2908. form = forms.InventoryItemRoleBulkEditForm
  2909. @register_model_view(InventoryItemRole, 'bulk_rename', path='rename', detail=False)
  2910. class InventoryItemRoleBulkRenameView(generic.BulkRenameView):
  2911. queryset = InventoryItemRole.objects.all()
  2912. filterset = filtersets.InventoryItemRoleFilterSet
  2913. @register_model_view(InventoryItemRole, 'bulk_delete', path='delete', detail=False)
  2914. class InventoryItemRoleBulkDeleteView(generic.BulkDeleteView):
  2915. queryset = InventoryItemRole.objects.annotate(
  2916. inventoryitem_count=count_related(InventoryItem, 'role'),
  2917. )
  2918. filterset = filtersets.InventoryItemRoleFilterSet
  2919. table = tables.InventoryItemRoleTable
  2920. #
  2921. # Bulk Device component creation
  2922. #
  2923. class DeviceBulkAddConsolePortView(generic.BulkComponentCreateView):
  2924. parent_model = Device
  2925. parent_field = 'device'
  2926. form = forms.ConsolePortBulkCreateForm
  2927. queryset = ConsolePort.objects.all()
  2928. model_form = forms.ConsolePortForm
  2929. filterset = filtersets.DeviceFilterSet
  2930. table = tables.DeviceTable
  2931. default_return_url = 'dcim:device_list'
  2932. class DeviceBulkAddConsoleServerPortView(generic.BulkComponentCreateView):
  2933. parent_model = Device
  2934. parent_field = 'device'
  2935. form = forms.ConsoleServerPortBulkCreateForm
  2936. queryset = ConsoleServerPort.objects.all()
  2937. model_form = forms.ConsoleServerPortForm
  2938. filterset = filtersets.DeviceFilterSet
  2939. table = tables.DeviceTable
  2940. default_return_url = 'dcim:device_list'
  2941. class DeviceBulkAddPowerPortView(generic.BulkComponentCreateView):
  2942. parent_model = Device
  2943. parent_field = 'device'
  2944. form = forms.PowerPortBulkCreateForm
  2945. queryset = PowerPort.objects.all()
  2946. model_form = forms.PowerPortForm
  2947. filterset = filtersets.DeviceFilterSet
  2948. table = tables.DeviceTable
  2949. default_return_url = 'dcim:device_list'
  2950. class DeviceBulkAddPowerOutletView(generic.BulkComponentCreateView):
  2951. parent_model = Device
  2952. parent_field = 'device'
  2953. form = forms.PowerOutletBulkCreateForm
  2954. queryset = PowerOutlet.objects.all()
  2955. model_form = forms.PowerOutletForm
  2956. filterset = filtersets.DeviceFilterSet
  2957. table = tables.DeviceTable
  2958. default_return_url = 'dcim:device_list'
  2959. class DeviceBulkAddInterfaceView(generic.BulkComponentCreateView):
  2960. parent_model = Device
  2961. parent_field = 'device'
  2962. form = forms.InterfaceBulkCreateForm
  2963. queryset = Interface.objects.all()
  2964. model_form = forms.InterfaceForm
  2965. filterset = filtersets.DeviceFilterSet
  2966. table = tables.DeviceTable
  2967. default_return_url = 'dcim:device_list'
  2968. class DeviceBulkAddRearPortView(generic.BulkComponentCreateView):
  2969. parent_model = Device
  2970. parent_field = 'device'
  2971. form = forms.RearPortBulkCreateForm
  2972. queryset = RearPort.objects.all()
  2973. model_form = forms.RearPortForm
  2974. filterset = filtersets.DeviceFilterSet
  2975. table = tables.DeviceTable
  2976. default_return_url = 'dcim:device_list'
  2977. class DeviceBulkAddModuleBayView(generic.BulkComponentCreateView):
  2978. parent_model = Device
  2979. parent_field = 'device'
  2980. form = forms.ModuleBayBulkCreateForm
  2981. queryset = ModuleBay.objects.all()
  2982. model_form = forms.ModuleBayForm
  2983. filterset = filtersets.DeviceFilterSet
  2984. table = tables.DeviceTable
  2985. default_return_url = 'dcim:device_list'
  2986. class DeviceBulkAddDeviceBayView(generic.BulkComponentCreateView):
  2987. parent_model = Device
  2988. parent_field = 'device'
  2989. form = forms.DeviceBayBulkCreateForm
  2990. queryset = DeviceBay.objects.all()
  2991. model_form = forms.DeviceBayForm
  2992. filterset = filtersets.DeviceFilterSet
  2993. table = tables.DeviceTable
  2994. default_return_url = 'dcim:device_list'
  2995. class DeviceBulkAddInventoryItemView(generic.BulkComponentCreateView):
  2996. parent_model = Device
  2997. parent_field = 'device'
  2998. form = forms.InventoryItemBulkCreateForm
  2999. queryset = InventoryItem.objects.all()
  3000. model_form = forms.InventoryItemForm
  3001. filterset = filtersets.DeviceFilterSet
  3002. table = tables.DeviceTable
  3003. default_return_url = 'dcim:device_list'
  3004. #
  3005. # Cables
  3006. #
  3007. @register_model_view(Cable, 'list', path='', detail=False)
  3008. class CableListView(generic.ObjectListView):
  3009. queryset = Cable.objects.prefetch_related(
  3010. 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location',
  3011. 'terminations___site',
  3012. )
  3013. filterset = filtersets.CableFilterSet
  3014. filterset_form = forms.CableFilterForm
  3015. table = tables.CableTable
  3016. @register_model_view(Cable)
  3017. class CableView(generic.ObjectView):
  3018. queryset = Cable.objects.all()
  3019. @register_model_view(Cable, 'add', detail=False)
  3020. @register_model_view(Cable, 'edit')
  3021. class CableEditView(generic.ObjectEditView):
  3022. queryset = Cable.objects.all()
  3023. template_name = 'dcim/cable_edit.html'
  3024. htmx_template_name = 'dcim/htmx/cable_edit.html'
  3025. def alter_object(self, obj, request, url_args, url_kwargs):
  3026. """
  3027. Hack into alter_object() to set the form class when editing an existing Cable, since ObjectEditView
  3028. doesn't currently provide a hook for dynamic class resolution.
  3029. """
  3030. a_terminations_type = CABLE_TERMINATION_TYPES.get(
  3031. request.POST.get('a_terminations_type') or request.GET.get('a_terminations_type')
  3032. )
  3033. b_terminations_type = CABLE_TERMINATION_TYPES.get(
  3034. request.POST.get('b_terminations_type') or request.GET.get('b_terminations_type')
  3035. )
  3036. if obj.pk:
  3037. if not a_terminations_type and (termination_a := obj.terminations.filter(cable_end='A').first()):
  3038. a_terminations_type = termination_a.termination._meta.model
  3039. if not b_terminations_type and (termination_b := obj.terminations.filter(cable_end='B').first()):
  3040. b_terminations_type = termination_b.termination._meta.model
  3041. self.form = forms.get_cable_form(a_terminations_type, b_terminations_type)
  3042. return super().alter_object(obj, request, url_args, url_kwargs)
  3043. def get_extra_addanother_params(self, request):
  3044. params = {
  3045. 'a_terminations_type': request.GET.get('a_terminations_type'),
  3046. 'b_terminations_type': request.GET.get('b_terminations_type')
  3047. }
  3048. for key in request.POST:
  3049. if 'device' in key or 'power_panel' in key or 'circuit' in key:
  3050. params.update({key: request.POST.get(key)})
  3051. return params
  3052. @register_model_view(Cable, 'delete')
  3053. class CableDeleteView(generic.ObjectDeleteView):
  3054. queryset = Cable.objects.all()
  3055. @register_model_view(Cable, 'bulk_import', path='import', detail=False)
  3056. class CableBulkImportView(generic.BulkImportView):
  3057. queryset = Cable.objects.all()
  3058. model_form = forms.CableImportForm
  3059. @register_model_view(Cable, 'bulk_edit', path='edit', detail=False)
  3060. class CableBulkEditView(generic.BulkEditView):
  3061. queryset = Cable.objects.prefetch_related(
  3062. 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location',
  3063. 'terminations___site',
  3064. )
  3065. filterset = filtersets.CableFilterSet
  3066. table = tables.CableTable
  3067. form = forms.CableBulkEditForm
  3068. @register_model_view(Cable, 'bulk_rename', path='rename', detail=False)
  3069. class CableBulkRenameView(generic.BulkRenameView):
  3070. queryset = Cable.objects.all()
  3071. field_name = 'label'
  3072. filterset = filtersets.CableFilterSet
  3073. @register_model_view(Cable, 'bulk_delete', path='delete', detail=False)
  3074. class CableBulkDeleteView(generic.BulkDeleteView):
  3075. queryset = Cable.objects.prefetch_related(
  3076. 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location',
  3077. 'terminations___site',
  3078. )
  3079. filterset = filtersets.CableFilterSet
  3080. table = tables.CableTable
  3081. #
  3082. # Connections
  3083. #
  3084. class ConsoleConnectionsListView(generic.ObjectListView):
  3085. queryset = ConsolePort.objects.filter(_path__is_complete=True)
  3086. filterset = filtersets.ConsoleConnectionFilterSet
  3087. filterset_form = forms.ConsoleConnectionFilterForm
  3088. table = tables.ConsoleConnectionTable
  3089. template_name = 'dcim/connections_list.html'
  3090. actions = (BulkExport,)
  3091. def get_extra_context(self, request):
  3092. return {
  3093. 'title': 'Console Connections'
  3094. }
  3095. class PowerConnectionsListView(generic.ObjectListView):
  3096. queryset = PowerPort.objects.filter(_path__is_complete=True)
  3097. filterset = filtersets.PowerConnectionFilterSet
  3098. filterset_form = forms.PowerConnectionFilterForm
  3099. table = tables.PowerConnectionTable
  3100. template_name = 'dcim/connections_list.html'
  3101. actions = (BulkExport,)
  3102. def get_extra_context(self, request):
  3103. return {
  3104. 'title': 'Power Connections'
  3105. }
  3106. class InterfaceConnectionsListView(generic.ObjectListView):
  3107. queryset = Interface.objects.filter(_path__is_complete=True)
  3108. filterset = filtersets.InterfaceConnectionFilterSet
  3109. filterset_form = forms.InterfaceConnectionFilterForm
  3110. table = tables.InterfaceConnectionTable
  3111. template_name = 'dcim/connections_list.html'
  3112. actions = (BulkExport,)
  3113. def get_extra_context(self, request):
  3114. return {
  3115. 'title': 'Interface Connections'
  3116. }
  3117. #
  3118. # Virtual chassis
  3119. #
  3120. @register_model_view(VirtualChassis, 'list', path='', detail=False)
  3121. class VirtualChassisListView(generic.ObjectListView):
  3122. queryset = VirtualChassis.objects.all()
  3123. table = tables.VirtualChassisTable
  3124. filterset = filtersets.VirtualChassisFilterSet
  3125. filterset_form = forms.VirtualChassisFilterForm
  3126. @register_model_view(VirtualChassis)
  3127. class VirtualChassisView(generic.ObjectView):
  3128. queryset = VirtualChassis.objects.all()
  3129. def get_extra_context(self, request, instance):
  3130. members = Device.objects.restrict(request.user).filter(virtual_chassis=instance)
  3131. return {
  3132. 'members': members,
  3133. }
  3134. @register_model_view(VirtualChassis, 'add', detail=False)
  3135. class VirtualChassisCreateView(generic.ObjectEditView):
  3136. queryset = VirtualChassis.objects.all()
  3137. form = forms.VirtualChassisCreateForm
  3138. @register_model_view(VirtualChassis, 'edit')
  3139. class VirtualChassisEditView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  3140. queryset = VirtualChassis.objects.all()
  3141. def get_required_permission(self):
  3142. return 'dcim.change_virtualchassis'
  3143. def get(self, request, pk):
  3144. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  3145. VCMemberFormSet = modelformset_factory(
  3146. model=Device,
  3147. form=forms.DeviceVCMembershipForm,
  3148. formset=forms.BaseVCMemberFormSet,
  3149. extra=0
  3150. )
  3151. members_queryset = virtual_chassis.members.prefetch_related('rack').order_by('vc_position')
  3152. vc_form = forms.VirtualChassisForm(instance=virtual_chassis)
  3153. vc_form.fields['master'].queryset = members_queryset
  3154. formset = VCMemberFormSet(queryset=members_queryset)
  3155. return render(request, 'dcim/virtualchassis_edit.html', {
  3156. 'object': virtual_chassis,
  3157. 'vc_form': vc_form,
  3158. 'formset': formset,
  3159. 'return_url': self.get_return_url(request, virtual_chassis),
  3160. })
  3161. def post(self, request, pk):
  3162. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  3163. virtual_chassis.snapshot()
  3164. VCMemberFormSet = modelformset_factory(
  3165. model=Device,
  3166. form=forms.DeviceVCMembershipForm,
  3167. formset=forms.BaseVCMemberFormSet,
  3168. extra=0
  3169. )
  3170. members_queryset = virtual_chassis.members.prefetch_related('rack').order_by('vc_position')
  3171. vc_form = forms.VirtualChassisForm(request.POST, instance=virtual_chassis)
  3172. vc_form.fields['master'].queryset = members_queryset
  3173. formset = VCMemberFormSet(request.POST, queryset=members_queryset)
  3174. if vc_form.is_valid() and formset.is_valid():
  3175. virtual_chassis._changelog_message = vc_form.cleaned_data.pop('changelog_message', '')
  3176. with transaction.atomic(using=router.db_for_write(Device)):
  3177. # Save the VirtualChassis
  3178. vc_form.save()
  3179. # Nullify the vc_position of each member first to allow reordering without raising an IntegrityError on
  3180. # duplicate positions. Then save each member instance.
  3181. members = formset.save(commit=False)
  3182. devices = Device.objects.filter(pk__in=[m.pk for m in members])
  3183. for device in devices:
  3184. device.vc_position = None
  3185. device.save()
  3186. for member in members:
  3187. member.save()
  3188. return redirect(virtual_chassis.get_absolute_url())
  3189. return render(request, 'dcim/virtualchassis_edit.html', {
  3190. 'vc_form': vc_form,
  3191. 'formset': formset,
  3192. 'return_url': self.get_return_url(request, virtual_chassis),
  3193. })
  3194. @register_model_view(VirtualChassis, 'delete')
  3195. class VirtualChassisDeleteView(generic.ObjectDeleteView):
  3196. queryset = VirtualChassis.objects.all()
  3197. @register_model_view(VirtualChassis, 'add_member', path='add-member')
  3198. class VirtualChassisAddMemberView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  3199. queryset = VirtualChassis.objects.all()
  3200. def get_required_permission(self):
  3201. return 'dcim.change_virtualchassis'
  3202. def get(self, request, pk):
  3203. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  3204. initial_data = {k: request.GET[k] for k in request.GET}
  3205. member_select_form = forms.VCMemberSelectForm(initial=initial_data)
  3206. membership_form = forms.DeviceVCMembershipForm(initial=initial_data)
  3207. return render(request, 'dcim/virtualchassis_add_member.html', {
  3208. 'virtual_chassis': virtual_chassis,
  3209. 'member_select_form': member_select_form,
  3210. 'membership_form': membership_form,
  3211. 'return_url': self.get_return_url(request, virtual_chassis),
  3212. })
  3213. def post(self, request, pk):
  3214. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  3215. member_select_form = forms.VCMemberSelectForm(request.POST)
  3216. if member_select_form.is_valid():
  3217. device = member_select_form.cleaned_data['device']
  3218. device.snapshot()
  3219. device.virtual_chassis = virtual_chassis
  3220. data = {
  3221. 'vc_position': request.POST['vc_position'],
  3222. 'vc_priority': request.POST['vc_priority'],
  3223. }
  3224. membership_form = forms.DeviceVCMembershipForm(data=data, validate_vc_position=True, instance=device)
  3225. if membership_form.is_valid():
  3226. membership_form.save()
  3227. messages.success(request, mark_safe(
  3228. _('Added member <a href="{url}">{device}</a>').format(
  3229. url=device.get_absolute_url(), device=escape(device)
  3230. )
  3231. ))
  3232. if '_addanother' in request.POST and safe_for_redirect(request.get_full_path()):
  3233. return redirect(request.get_full_path())
  3234. return redirect(self.get_return_url(request, device))
  3235. else:
  3236. membership_form = forms.DeviceVCMembershipForm(data=request.POST)
  3237. return render(request, 'dcim/virtualchassis_add_member.html', {
  3238. 'virtual_chassis': virtual_chassis,
  3239. 'member_select_form': member_select_form,
  3240. 'membership_form': membership_form,
  3241. 'return_url': self.get_return_url(request, virtual_chassis),
  3242. })
  3243. class VirtualChassisRemoveMemberView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  3244. queryset = Device.objects.all()
  3245. def get_required_permission(self):
  3246. return 'dcim.change_device'
  3247. def get(self, request, pk):
  3248. device = get_object_or_404(self.queryset, pk=pk, virtual_chassis__isnull=False)
  3249. form = ConfirmationForm(initial=request.GET)
  3250. return render(request, 'dcim/virtualchassis_remove_member.html', {
  3251. 'device': device,
  3252. 'form': form,
  3253. 'return_url': self.get_return_url(request, device),
  3254. })
  3255. def post(self, request, pk):
  3256. device = get_object_or_404(self.queryset, pk=pk, virtual_chassis__isnull=False)
  3257. form = ConfirmationForm(request.POST)
  3258. # Protect master device from being removed
  3259. virtual_chassis = VirtualChassis.objects.filter(master=device).first()
  3260. if virtual_chassis is not None:
  3261. messages.error(
  3262. request,
  3263. _('Unable to remove master device {device} from the virtual chassis.').format(device=device)
  3264. )
  3265. return redirect(device.get_absolute_url())
  3266. if form.is_valid():
  3267. device.snapshot()
  3268. device.virtual_chassis = None
  3269. device.vc_position = None
  3270. device.vc_priority = None
  3271. device.save()
  3272. msg = _('Removed {device} from virtual chassis {chassis}').format(
  3273. device=device,
  3274. chassis=device.virtual_chassis
  3275. )
  3276. messages.success(request, msg)
  3277. return redirect(self.get_return_url(request, device))
  3278. return render(request, 'dcim/virtualchassis_remove_member.html', {
  3279. 'device': device,
  3280. 'form': form,
  3281. 'return_url': self.get_return_url(request, device),
  3282. })
  3283. @register_model_view(VirtualChassis, 'bulk_import', path='import', detail=False)
  3284. class VirtualChassisBulkImportView(generic.BulkImportView):
  3285. queryset = VirtualChassis.objects.all()
  3286. model_form = forms.VirtualChassisImportForm
  3287. @register_model_view(VirtualChassis, 'bulk_edit', path='edit', detail=False)
  3288. class VirtualChassisBulkEditView(generic.BulkEditView):
  3289. queryset = VirtualChassis.objects.all()
  3290. filterset = filtersets.VirtualChassisFilterSet
  3291. table = tables.VirtualChassisTable
  3292. form = forms.VirtualChassisBulkEditForm
  3293. @register_model_view(VirtualChassis, 'bulk_rename', path='rename', detail=False)
  3294. class VirtualChassisBulkRenameView(generic.BulkRenameView):
  3295. queryset = VirtualChassis.objects.all()
  3296. filterset = filtersets.VirtualChassisFilterSet
  3297. @register_model_view(VirtualChassis, 'bulk_delete', path='delete', detail=False)
  3298. class VirtualChassisBulkDeleteView(generic.BulkDeleteView):
  3299. queryset = VirtualChassis.objects.all()
  3300. filterset = filtersets.VirtualChassisFilterSet
  3301. table = tables.VirtualChassisTable
  3302. #
  3303. # Power panels
  3304. #
  3305. @register_model_view(PowerPanel, 'list', path='', detail=False)
  3306. class PowerPanelListView(generic.ObjectListView):
  3307. queryset = PowerPanel.objects.annotate(
  3308. powerfeed_count=count_related(PowerFeed, 'power_panel')
  3309. )
  3310. filterset = filtersets.PowerPanelFilterSet
  3311. filterset_form = forms.PowerPanelFilterForm
  3312. table = tables.PowerPanelTable
  3313. @register_model_view(PowerPanel)
  3314. class PowerPanelView(GetRelatedModelsMixin, generic.ObjectView):
  3315. queryset = PowerPanel.objects.all()
  3316. def get_extra_context(self, request, instance):
  3317. return {
  3318. 'related_models': self.get_related_models(request, instance),
  3319. }
  3320. @register_model_view(PowerPanel, 'add', detail=False)
  3321. @register_model_view(PowerPanel, 'edit')
  3322. class PowerPanelEditView(generic.ObjectEditView):
  3323. queryset = PowerPanel.objects.all()
  3324. form = forms.PowerPanelForm
  3325. @register_model_view(PowerPanel, 'delete')
  3326. class PowerPanelDeleteView(generic.ObjectDeleteView):
  3327. queryset = PowerPanel.objects.all()
  3328. @register_model_view(PowerPanel, 'bulk_import', path='import', detail=False)
  3329. class PowerPanelBulkImportView(generic.BulkImportView):
  3330. queryset = PowerPanel.objects.all()
  3331. model_form = forms.PowerPanelImportForm
  3332. @register_model_view(PowerPanel, 'bulk_edit', path='edit', detail=False)
  3333. class PowerPanelBulkEditView(generic.BulkEditView):
  3334. queryset = PowerPanel.objects.all()
  3335. filterset = filtersets.PowerPanelFilterSet
  3336. table = tables.PowerPanelTable
  3337. form = forms.PowerPanelBulkEditForm
  3338. @register_model_view(PowerPanel, 'bulk_rename', path='rename', detail=False)
  3339. class PowerPanelBulkRenameView(generic.BulkRenameView):
  3340. queryset = PowerPanel.objects.all()
  3341. filterset = filtersets.PowerPanelFilterSet
  3342. @register_model_view(PowerPanel, 'bulk_delete', path='delete', detail=False)
  3343. class PowerPanelBulkDeleteView(generic.BulkDeleteView):
  3344. queryset = PowerPanel.objects.annotate(
  3345. powerfeed_count=count_related(PowerFeed, 'power_panel')
  3346. )
  3347. filterset = filtersets.PowerPanelFilterSet
  3348. table = tables.PowerPanelTable
  3349. #
  3350. # Power feeds
  3351. #
  3352. @register_model_view(PowerFeed, 'list', path='', detail=False)
  3353. class PowerFeedListView(generic.ObjectListView):
  3354. queryset = PowerFeed.objects.all()
  3355. filterset = filtersets.PowerFeedFilterSet
  3356. filterset_form = forms.PowerFeedFilterForm
  3357. table = tables.PowerFeedTable
  3358. @register_model_view(PowerFeed)
  3359. class PowerFeedView(generic.ObjectView):
  3360. queryset = PowerFeed.objects.all()
  3361. @register_model_view(PowerFeed, 'add', detail=False)
  3362. @register_model_view(PowerFeed, 'edit')
  3363. class PowerFeedEditView(generic.ObjectEditView):
  3364. queryset = PowerFeed.objects.all()
  3365. form = forms.PowerFeedForm
  3366. @register_model_view(PowerFeed, 'delete')
  3367. class PowerFeedDeleteView(generic.ObjectDeleteView):
  3368. queryset = PowerFeed.objects.all()
  3369. @register_model_view(PowerFeed, 'bulk_import', path='import', detail=False)
  3370. class PowerFeedBulkImportView(generic.BulkImportView):
  3371. queryset = PowerFeed.objects.all()
  3372. model_form = forms.PowerFeedImportForm
  3373. @register_model_view(PowerFeed, 'bulk_edit', path='edit', detail=False)
  3374. class PowerFeedBulkEditView(generic.BulkEditView):
  3375. queryset = PowerFeed.objects.all()
  3376. filterset = filtersets.PowerFeedFilterSet
  3377. table = tables.PowerFeedTable
  3378. form = forms.PowerFeedBulkEditForm
  3379. @register_model_view(PowerFeed, 'bulk_rename', path='rename', detail=False)
  3380. class PowerFeedBulkRenameView(generic.BulkRenameView):
  3381. queryset = PowerFeed.objects.all()
  3382. filterset = filtersets.PowerFeedFilterSet
  3383. @register_model_view(PowerFeed, 'bulk_disconnect', path='disconnect', detail=False)
  3384. class PowerFeedBulkDisconnectView(BulkDisconnectView):
  3385. queryset = PowerFeed.objects.all()
  3386. @register_model_view(PowerFeed, 'bulk_delete', path='delete', detail=False)
  3387. class PowerFeedBulkDeleteView(generic.BulkDeleteView):
  3388. queryset = PowerFeed.objects.all()
  3389. filterset = filtersets.PowerFeedFilterSet
  3390. table = tables.PowerFeedTable
  3391. # Trace view
  3392. register_model_view(PowerFeed, 'trace', kwargs={'model': PowerFeed})(PathTraceView)
  3393. #
  3394. # Virtual device contexts
  3395. #
  3396. @register_model_view(VirtualDeviceContext, 'list', path='', detail=False)
  3397. class VirtualDeviceContextListView(generic.ObjectListView):
  3398. queryset = VirtualDeviceContext.objects.annotate(
  3399. interface_count=count_related(Interface, 'vdcs'),
  3400. )
  3401. filterset = filtersets.VirtualDeviceContextFilterSet
  3402. filterset_form = forms.VirtualDeviceContextFilterForm
  3403. table = tables.VirtualDeviceContextTable
  3404. actions = (AddObject, BulkImport, BulkEdit, BulkRename, BulkExport, BulkDelete)
  3405. @register_model_view(VirtualDeviceContext)
  3406. class VirtualDeviceContextView(GetRelatedModelsMixin, generic.ObjectView):
  3407. queryset = VirtualDeviceContext.objects.all()
  3408. def get_extra_context(self, request, instance):
  3409. return {
  3410. 'related_models': self.get_related_models(
  3411. request,
  3412. instance,
  3413. extra=(
  3414. (Interface.objects.restrict(request.user, 'view').filter(vdcs__in=[instance]), 'vdc_id'),
  3415. ),
  3416. ),
  3417. }
  3418. @register_model_view(VirtualDeviceContext, 'add', detail=False)
  3419. @register_model_view(VirtualDeviceContext, 'edit')
  3420. class VirtualDeviceContextEditView(generic.ObjectEditView):
  3421. queryset = VirtualDeviceContext.objects.all()
  3422. form = forms.VirtualDeviceContextForm
  3423. @register_model_view(VirtualDeviceContext, 'delete')
  3424. class VirtualDeviceContextDeleteView(generic.ObjectDeleteView):
  3425. queryset = VirtualDeviceContext.objects.all()
  3426. @register_model_view(VirtualDeviceContext, 'bulk_import', path='import', detail=False)
  3427. class VirtualDeviceContextBulkImportView(generic.BulkImportView):
  3428. queryset = VirtualDeviceContext.objects.all()
  3429. model_form = forms.VirtualDeviceContextImportForm
  3430. @register_model_view(VirtualDeviceContext, 'bulk_edit', path='edit', detail=False)
  3431. class VirtualDeviceContextBulkEditView(generic.BulkEditView):
  3432. queryset = VirtualDeviceContext.objects.all()
  3433. filterset = filtersets.VirtualDeviceContextFilterSet
  3434. table = tables.VirtualDeviceContextTable
  3435. form = forms.VirtualDeviceContextBulkEditForm
  3436. @register_model_view(VirtualDeviceContext, 'bulk_rename', path='rename', detail=False)
  3437. class VirtualDeviceContextBulkRenameView(generic.BulkRenameView):
  3438. queryset = VirtualDeviceContext.objects.all()
  3439. filterset = filtersets.VirtualDeviceContextFilterSet
  3440. @register_model_view(VirtualDeviceContext, 'bulk_delete', path='delete', detail=False)
  3441. class VirtualDeviceContextBulkDeleteView(generic.BulkDeleteView):
  3442. queryset = VirtualDeviceContext.objects.all()
  3443. filterset = filtersets.VirtualDeviceContextFilterSet
  3444. table = tables.VirtualDeviceContextTable
  3445. #
  3446. # MAC addresses
  3447. #
  3448. @register_model_view(MACAddress, 'list', path='', detail=False)
  3449. class MACAddressListView(generic.ObjectListView):
  3450. queryset = MACAddress.objects.all()
  3451. filterset = filtersets.MACAddressFilterSet
  3452. filterset_form = forms.MACAddressFilterForm
  3453. table = tables.MACAddressTable
  3454. actions = (AddObject, BulkImport, BulkExport, BulkEdit, BulkDelete)
  3455. @register_model_view(MACAddress)
  3456. class MACAddressView(generic.ObjectView):
  3457. queryset = MACAddress.objects.all()
  3458. @register_model_view(MACAddress, 'add', detail=False)
  3459. @register_model_view(MACAddress, 'edit')
  3460. class MACAddressEditView(generic.ObjectEditView):
  3461. queryset = MACAddress.objects.all()
  3462. form = forms.MACAddressForm
  3463. @register_model_view(MACAddress, 'delete')
  3464. class MACAddressDeleteView(generic.ObjectDeleteView):
  3465. queryset = MACAddress.objects.all()
  3466. @register_model_view(MACAddress, 'bulk_import', path='import', detail=False)
  3467. class MACAddressBulkImportView(generic.BulkImportView):
  3468. queryset = MACAddress.objects.all()
  3469. model_form = forms.MACAddressImportForm
  3470. @register_model_view(MACAddress, 'bulk_edit', path='edit', detail=False)
  3471. class MACAddressBulkEditView(generic.BulkEditView):
  3472. queryset = MACAddress.objects.all()
  3473. filterset = filtersets.MACAddressFilterSet
  3474. table = tables.MACAddressTable
  3475. form = forms.MACAddressBulkEditForm
  3476. @register_model_view(MACAddress, 'bulk_delete', path='delete', detail=False)
  3477. class MACAddressBulkDeleteView(generic.BulkDeleteView):
  3478. queryset = MACAddress.objects.all()
  3479. filterset = filtersets.MACAddressFilterSet
  3480. table = tables.MACAddressTable