views.py 149 KB

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