views.py 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. from django.contrib.contenttypes.models import ContentType
  2. from django.db.models import Prefetch
  3. from django.db.models.expressions import RawSQL
  4. from django.shortcuts import get_object_or_404, redirect, render
  5. from django.urls import reverse
  6. from django.utils.translation import gettext as _
  7. from circuits.models import Provider
  8. from dcim.filtersets import InterfaceFilterSet
  9. from dcim.models import Interface, Site
  10. from netbox.views import generic
  11. from utilities.utils import count_related
  12. from utilities.views import ViewTab, register_model_view
  13. from virtualization.filtersets import VMInterfaceFilterSet
  14. from virtualization.models import VMInterface
  15. from . import filtersets, forms, tables
  16. from .choices import PrefixStatusChoices
  17. from .constants import *
  18. from .models import *
  19. from .tables.l2vpn import L2VPNTable, L2VPNTerminationTable
  20. from .utils import add_requested_prefixes, add_available_ipaddresses, add_available_vlans
  21. #
  22. # VRFs
  23. #
  24. class VRFListView(generic.ObjectListView):
  25. queryset = VRF.objects.all()
  26. filterset = filtersets.VRFFilterSet
  27. filterset_form = forms.VRFFilterForm
  28. table = tables.VRFTable
  29. @register_model_view(VRF)
  30. class VRFView(generic.ObjectView):
  31. queryset = VRF.objects.all()
  32. def get_extra_context(self, request, instance):
  33. related_models = (
  34. (Prefix.objects.restrict(request.user, 'view').filter(vrf=instance), 'vrf_id'),
  35. (IPAddress.objects.restrict(request.user, 'view').filter(vrf=instance), 'vrf_id'),
  36. )
  37. import_targets_table = tables.RouteTargetTable(
  38. instance.import_targets.all(),
  39. orderable=False
  40. )
  41. export_targets_table = tables.RouteTargetTable(
  42. instance.export_targets.all(),
  43. orderable=False
  44. )
  45. return {
  46. 'related_models': related_models,
  47. 'import_targets_table': import_targets_table,
  48. 'export_targets_table': export_targets_table,
  49. }
  50. @register_model_view(VRF, 'edit')
  51. class VRFEditView(generic.ObjectEditView):
  52. queryset = VRF.objects.all()
  53. form = forms.VRFForm
  54. @register_model_view(VRF, 'delete')
  55. class VRFDeleteView(generic.ObjectDeleteView):
  56. queryset = VRF.objects.all()
  57. class VRFBulkImportView(generic.BulkImportView):
  58. queryset = VRF.objects.all()
  59. model_form = forms.VRFImportForm
  60. class VRFBulkEditView(generic.BulkEditView):
  61. queryset = VRF.objects.all()
  62. filterset = filtersets.VRFFilterSet
  63. table = tables.VRFTable
  64. form = forms.VRFBulkEditForm
  65. class VRFBulkDeleteView(generic.BulkDeleteView):
  66. queryset = VRF.objects.all()
  67. filterset = filtersets.VRFFilterSet
  68. table = tables.VRFTable
  69. #
  70. # Route targets
  71. #
  72. class RouteTargetListView(generic.ObjectListView):
  73. queryset = RouteTarget.objects.all()
  74. filterset = filtersets.RouteTargetFilterSet
  75. filterset_form = forms.RouteTargetFilterForm
  76. table = tables.RouteTargetTable
  77. @register_model_view(RouteTarget)
  78. class RouteTargetView(generic.ObjectView):
  79. queryset = RouteTarget.objects.all()
  80. @register_model_view(RouteTarget, 'edit')
  81. class RouteTargetEditView(generic.ObjectEditView):
  82. queryset = RouteTarget.objects.all()
  83. form = forms.RouteTargetForm
  84. @register_model_view(RouteTarget, 'delete')
  85. class RouteTargetDeleteView(generic.ObjectDeleteView):
  86. queryset = RouteTarget.objects.all()
  87. class RouteTargetBulkImportView(generic.BulkImportView):
  88. queryset = RouteTarget.objects.all()
  89. model_form = forms.RouteTargetImportForm
  90. class RouteTargetBulkEditView(generic.BulkEditView):
  91. queryset = RouteTarget.objects.all()
  92. filterset = filtersets.RouteTargetFilterSet
  93. table = tables.RouteTargetTable
  94. form = forms.RouteTargetBulkEditForm
  95. class RouteTargetBulkDeleteView(generic.BulkDeleteView):
  96. queryset = RouteTarget.objects.all()
  97. filterset = filtersets.RouteTargetFilterSet
  98. table = tables.RouteTargetTable
  99. #
  100. # RIRs
  101. #
  102. class RIRListView(generic.ObjectListView):
  103. queryset = RIR.objects.annotate(
  104. aggregate_count=count_related(Aggregate, 'rir')
  105. )
  106. filterset = filtersets.RIRFilterSet
  107. filterset_form = forms.RIRFilterForm
  108. table = tables.RIRTable
  109. @register_model_view(RIR)
  110. class RIRView(generic.ObjectView):
  111. queryset = RIR.objects.all()
  112. def get_extra_context(self, request, instance):
  113. related_models = (
  114. (Aggregate.objects.restrict(request.user, 'view').filter(rir=instance), 'rir_id'),
  115. )
  116. return {
  117. 'related_models': related_models,
  118. }
  119. @register_model_view(RIR, 'edit')
  120. class RIREditView(generic.ObjectEditView):
  121. queryset = RIR.objects.all()
  122. form = forms.RIRForm
  123. @register_model_view(RIR, 'delete')
  124. class RIRDeleteView(generic.ObjectDeleteView):
  125. queryset = RIR.objects.all()
  126. class RIRBulkImportView(generic.BulkImportView):
  127. queryset = RIR.objects.all()
  128. model_form = forms.RIRImportForm
  129. class RIRBulkEditView(generic.BulkEditView):
  130. queryset = RIR.objects.annotate(
  131. aggregate_count=count_related(Aggregate, 'rir')
  132. )
  133. filterset = filtersets.RIRFilterSet
  134. table = tables.RIRTable
  135. form = forms.RIRBulkEditForm
  136. class RIRBulkDeleteView(generic.BulkDeleteView):
  137. queryset = RIR.objects.annotate(
  138. aggregate_count=count_related(Aggregate, 'rir')
  139. )
  140. filterset = filtersets.RIRFilterSet
  141. table = tables.RIRTable
  142. #
  143. # ASN ranges
  144. #
  145. class ASNRangeListView(generic.ObjectListView):
  146. queryset = ASNRange.objects.all()
  147. filterset = filtersets.ASNRangeFilterSet
  148. filterset_form = forms.ASNRangeFilterForm
  149. table = tables.ASNRangeTable
  150. @register_model_view(ASNRange)
  151. class ASNRangeView(generic.ObjectView):
  152. queryset = ASNRange.objects.all()
  153. @register_model_view(ASNRange, 'asns')
  154. class ASNRangeASNsView(generic.ObjectChildrenView):
  155. queryset = ASNRange.objects.all()
  156. child_model = ASN
  157. table = tables.ASNTable
  158. filterset = filtersets.ASNFilterSet
  159. template_name = 'ipam/asnrange/asns.html'
  160. tab = ViewTab(
  161. label=_('ASNs'),
  162. badge=lambda x: x.get_child_asns().count(),
  163. permission='ipam.view_asns',
  164. weight=500
  165. )
  166. def get_children(self, request, parent):
  167. return parent.get_child_asns().restrict(request.user, 'view').annotate(
  168. site_count=count_related(Site, 'asns'),
  169. provider_count=count_related(Provider, 'asns')
  170. )
  171. @register_model_view(ASNRange, 'edit')
  172. class ASNRangeEditView(generic.ObjectEditView):
  173. queryset = ASNRange.objects.all()
  174. form = forms.ASNRangeForm
  175. @register_model_view(ASNRange, 'delete')
  176. class ASNRangeDeleteView(generic.ObjectDeleteView):
  177. queryset = ASNRange.objects.all()
  178. class ASNRangeBulkImportView(generic.BulkImportView):
  179. queryset = ASNRange.objects.all()
  180. model_form = forms.ASNRangeImportForm
  181. class ASNRangeBulkEditView(generic.BulkEditView):
  182. queryset = ASNRange.objects.annotate(
  183. site_count=count_related(Site, 'asns')
  184. )
  185. filterset = filtersets.ASNRangeFilterSet
  186. table = tables.ASNRangeTable
  187. form = forms.ASNRangeBulkEditForm
  188. class ASNRangeBulkDeleteView(generic.BulkDeleteView):
  189. queryset = ASNRange.objects.annotate(
  190. site_count=count_related(Site, 'asns')
  191. )
  192. filterset = filtersets.ASNRangeFilterSet
  193. table = tables.ASNRangeTable
  194. #
  195. # ASNs
  196. #
  197. class ASNListView(generic.ObjectListView):
  198. queryset = ASN.objects.annotate(
  199. site_count=count_related(Site, 'asns'),
  200. provider_count=count_related(Provider, 'asns')
  201. )
  202. filterset = filtersets.ASNFilterSet
  203. filterset_form = forms.ASNFilterForm
  204. table = tables.ASNTable
  205. @register_model_view(ASN)
  206. class ASNView(generic.ObjectView):
  207. queryset = ASN.objects.all()
  208. def get_extra_context(self, request, instance):
  209. related_models = (
  210. (Site.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
  211. (Provider.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
  212. )
  213. return {
  214. 'related_models': related_models,
  215. }
  216. @register_model_view(ASN, 'edit')
  217. class ASNEditView(generic.ObjectEditView):
  218. queryset = ASN.objects.all()
  219. form = forms.ASNForm
  220. @register_model_view(ASN, 'delete')
  221. class ASNDeleteView(generic.ObjectDeleteView):
  222. queryset = ASN.objects.all()
  223. class ASNBulkImportView(generic.BulkImportView):
  224. queryset = ASN.objects.all()
  225. model_form = forms.ASNImportForm
  226. class ASNBulkEditView(generic.BulkEditView):
  227. queryset = ASN.objects.annotate(
  228. site_count=count_related(Site, 'asns')
  229. )
  230. filterset = filtersets.ASNFilterSet
  231. table = tables.ASNTable
  232. form = forms.ASNBulkEditForm
  233. class ASNBulkDeleteView(generic.BulkDeleteView):
  234. queryset = ASN.objects.annotate(
  235. site_count=count_related(Site, 'asns')
  236. )
  237. filterset = filtersets.ASNFilterSet
  238. table = tables.ASNTable
  239. #
  240. # Aggregates
  241. #
  242. class AggregateListView(generic.ObjectListView):
  243. queryset = Aggregate.objects.annotate(
  244. child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
  245. )
  246. filterset = filtersets.AggregateFilterSet
  247. filterset_form = forms.AggregateFilterForm
  248. table = tables.AggregateTable
  249. @register_model_view(Aggregate)
  250. class AggregateView(generic.ObjectView):
  251. queryset = Aggregate.objects.all()
  252. @register_model_view(Aggregate, 'prefixes')
  253. class AggregatePrefixesView(generic.ObjectChildrenView):
  254. queryset = Aggregate.objects.all()
  255. child_model = Prefix
  256. table = tables.PrefixTable
  257. filterset = filtersets.PrefixFilterSet
  258. template_name = 'ipam/aggregate/prefixes.html'
  259. tab = ViewTab(
  260. label=_('Prefixes'),
  261. badge=lambda x: x.get_child_prefixes().count(),
  262. permission='ipam.view_prefix',
  263. weight=500
  264. )
  265. def get_children(self, request, parent):
  266. return Prefix.objects.restrict(request.user, 'view').filter(
  267. prefix__net_contained_or_equal=str(parent.prefix)
  268. ).prefetch_related('site', 'role', 'tenant', 'tenant__group', 'vlan')
  269. def prep_table_data(self, request, queryset, parent):
  270. # Determine whether to show assigned prefixes, available prefixes, or both
  271. show_available = bool(request.GET.get('show_available', 'true') == 'true')
  272. show_assigned = bool(request.GET.get('show_assigned', 'true') == 'true')
  273. return add_requested_prefixes(parent.prefix, queryset, show_available, show_assigned)
  274. def get_extra_context(self, request, instance):
  275. return {
  276. 'bulk_querystring': f'within={instance.prefix}',
  277. 'first_available_prefix': instance.get_first_available_prefix(),
  278. 'show_available': bool(request.GET.get('show_available', 'true') == 'true'),
  279. 'show_assigned': bool(request.GET.get('show_assigned', 'true') == 'true'),
  280. }
  281. @register_model_view(Aggregate, 'edit')
  282. class AggregateEditView(generic.ObjectEditView):
  283. queryset = Aggregate.objects.all()
  284. form = forms.AggregateForm
  285. @register_model_view(Aggregate, 'delete')
  286. class AggregateDeleteView(generic.ObjectDeleteView):
  287. queryset = Aggregate.objects.all()
  288. class AggregateBulkImportView(generic.BulkImportView):
  289. queryset = Aggregate.objects.all()
  290. model_form = forms.AggregateImportForm
  291. class AggregateBulkEditView(generic.BulkEditView):
  292. queryset = Aggregate.objects.annotate(
  293. child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
  294. )
  295. filterset = filtersets.AggregateFilterSet
  296. table = tables.AggregateTable
  297. form = forms.AggregateBulkEditForm
  298. class AggregateBulkDeleteView(generic.BulkDeleteView):
  299. queryset = Aggregate.objects.annotate(
  300. child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
  301. )
  302. filterset = filtersets.AggregateFilterSet
  303. table = tables.AggregateTable
  304. #
  305. # Prefix/VLAN roles
  306. #
  307. class RoleListView(generic.ObjectListView):
  308. queryset = Role.objects.annotate(
  309. prefix_count=count_related(Prefix, 'role'),
  310. iprange_count=count_related(IPRange, 'role'),
  311. vlan_count=count_related(VLAN, 'role')
  312. )
  313. filterset = filtersets.RoleFilterSet
  314. filterset_form = forms.RoleFilterForm
  315. table = tables.RoleTable
  316. @register_model_view(Role)
  317. class RoleView(generic.ObjectView):
  318. queryset = Role.objects.all()
  319. def get_extra_context(self, request, instance):
  320. related_models = (
  321. (Prefix.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
  322. (IPRange.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
  323. (VLAN.objects.restrict(request.user, 'view').filter(role=instance), 'role_id'),
  324. )
  325. return {
  326. 'related_models': related_models,
  327. }
  328. @register_model_view(Role, 'edit')
  329. class RoleEditView(generic.ObjectEditView):
  330. queryset = Role.objects.all()
  331. form = forms.RoleForm
  332. @register_model_view(Role, 'delete')
  333. class RoleDeleteView(generic.ObjectDeleteView):
  334. queryset = Role.objects.all()
  335. class RoleBulkImportView(generic.BulkImportView):
  336. queryset = Role.objects.all()
  337. model_form = forms.RoleImportForm
  338. class RoleBulkEditView(generic.BulkEditView):
  339. queryset = Role.objects.all()
  340. filterset = filtersets.RoleFilterSet
  341. table = tables.RoleTable
  342. form = forms.RoleBulkEditForm
  343. class RoleBulkDeleteView(generic.BulkDeleteView):
  344. queryset = Role.objects.all()
  345. filterset = filtersets.RoleFilterSet
  346. table = tables.RoleTable
  347. #
  348. # Prefixes
  349. #
  350. class PrefixListView(generic.ObjectListView):
  351. queryset = Prefix.objects.all()
  352. filterset = filtersets.PrefixFilterSet
  353. filterset_form = forms.PrefixFilterForm
  354. table = tables.PrefixTable
  355. template_name = 'ipam/prefix_list.html'
  356. @register_model_view(Prefix)
  357. class PrefixView(generic.ObjectView):
  358. queryset = Prefix.objects.all()
  359. def get_extra_context(self, request, instance):
  360. try:
  361. aggregate = Aggregate.objects.restrict(request.user, 'view').get(
  362. prefix__net_contains_or_equals=str(instance.prefix)
  363. )
  364. except Aggregate.DoesNotExist:
  365. aggregate = None
  366. # Parent prefixes table
  367. parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  368. Q(vrf=instance.vrf) | Q(vrf__isnull=True, status=PrefixStatusChoices.STATUS_CONTAINER)
  369. ).filter(
  370. prefix__net_contains=str(instance.prefix)
  371. ).prefetch_related(
  372. 'site', 'role', 'tenant', 'vlan',
  373. )
  374. parent_prefix_table = tables.PrefixTable(
  375. list(parent_prefixes),
  376. exclude=('vrf', 'utilization'),
  377. orderable=False
  378. )
  379. # Duplicate prefixes table
  380. duplicate_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  381. vrf=instance.vrf, prefix=str(instance.prefix)
  382. ).exclude(
  383. pk=instance.pk
  384. ).prefetch_related(
  385. 'site', 'role', 'tenant', 'vlan',
  386. )
  387. duplicate_prefix_table = tables.PrefixTable(
  388. list(duplicate_prefixes),
  389. exclude=('vrf', 'utilization'),
  390. orderable=False
  391. )
  392. return {
  393. 'aggregate': aggregate,
  394. 'parent_prefix_table': parent_prefix_table,
  395. 'duplicate_prefix_table': duplicate_prefix_table,
  396. }
  397. @register_model_view(Prefix, 'prefixes')
  398. class PrefixPrefixesView(generic.ObjectChildrenView):
  399. queryset = Prefix.objects.all()
  400. child_model = Prefix
  401. table = tables.PrefixTable
  402. filterset = filtersets.PrefixFilterSet
  403. template_name = 'ipam/prefix/prefixes.html'
  404. tab = ViewTab(
  405. label=_('Child Prefixes'),
  406. badge=lambda x: x.get_child_prefixes().count(),
  407. permission='ipam.view_prefix',
  408. weight=500
  409. )
  410. def get_children(self, request, parent):
  411. return parent.get_child_prefixes().restrict(request.user, 'view').prefetch_related(
  412. 'site', 'vrf', 'vlan', 'role', 'tenant', 'tenant__group'
  413. )
  414. def prep_table_data(self, request, queryset, parent):
  415. # Determine whether to show assigned prefixes, available prefixes, or both
  416. show_available = bool(request.GET.get('show_available', 'true') == 'true')
  417. show_assigned = bool(request.GET.get('show_assigned', 'true') == 'true')
  418. return add_requested_prefixes(parent.prefix, queryset, show_available, show_assigned)
  419. def get_extra_context(self, request, instance):
  420. return {
  421. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&within={instance.prefix}",
  422. 'first_available_prefix': instance.get_first_available_prefix(),
  423. 'show_available': bool(request.GET.get('show_available', 'true') == 'true'),
  424. 'show_assigned': bool(request.GET.get('show_assigned', 'true') == 'true'),
  425. }
  426. @register_model_view(Prefix, 'ipranges', path='ip-ranges')
  427. class PrefixIPRangesView(generic.ObjectChildrenView):
  428. queryset = Prefix.objects.all()
  429. child_model = IPRange
  430. table = tables.IPRangeTable
  431. filterset = filtersets.IPRangeFilterSet
  432. template_name = 'ipam/prefix/ip_ranges.html'
  433. tab = ViewTab(
  434. label=_('Child Ranges'),
  435. badge=lambda x: x.get_child_ranges().count(),
  436. permission='ipam.view_iprange',
  437. weight=600
  438. )
  439. def get_children(self, request, parent):
  440. return parent.get_child_ranges().restrict(request.user, 'view').prefetch_related(
  441. 'tenant__group',
  442. )
  443. def get_extra_context(self, request, instance):
  444. return {
  445. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&parent={instance.prefix}",
  446. 'first_available_ip': instance.get_first_available_ip(),
  447. }
  448. @register_model_view(Prefix, 'ipaddresses', path='ip-addresses')
  449. class PrefixIPAddressesView(generic.ObjectChildrenView):
  450. queryset = Prefix.objects.all()
  451. child_model = IPAddress
  452. table = tables.IPAddressTable
  453. filterset = filtersets.IPAddressFilterSet
  454. template_name = 'ipam/prefix/ip_addresses.html'
  455. tab = ViewTab(
  456. label=_('IP Addresses'),
  457. badge=lambda x: x.get_child_ips().count(),
  458. permission='ipam.view_ipaddress',
  459. weight=700
  460. )
  461. def get_children(self, request, parent):
  462. return parent.get_child_ips().restrict(request.user, 'view').prefetch_related('vrf', 'tenant', 'tenant__group')
  463. def prep_table_data(self, request, queryset, parent):
  464. if not request.GET.get('q') and not request.GET.get('sort'):
  465. return add_available_ipaddresses(parent.prefix, queryset, parent.is_pool)
  466. return queryset
  467. def get_extra_context(self, request, instance):
  468. return {
  469. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&parent={instance.prefix}",
  470. 'first_available_ip': instance.get_first_available_ip(),
  471. }
  472. @register_model_view(Prefix, 'edit')
  473. class PrefixEditView(generic.ObjectEditView):
  474. queryset = Prefix.objects.all()
  475. form = forms.PrefixForm
  476. @register_model_view(Prefix, 'delete')
  477. class PrefixDeleteView(generic.ObjectDeleteView):
  478. queryset = Prefix.objects.all()
  479. class PrefixBulkImportView(generic.BulkImportView):
  480. queryset = Prefix.objects.all()
  481. model_form = forms.PrefixImportForm
  482. class PrefixBulkEditView(generic.BulkEditView):
  483. queryset = Prefix.objects.prefetch_related('vrf__tenant')
  484. filterset = filtersets.PrefixFilterSet
  485. table = tables.PrefixTable
  486. form = forms.PrefixBulkEditForm
  487. class PrefixBulkDeleteView(generic.BulkDeleteView):
  488. queryset = Prefix.objects.prefetch_related('vrf__tenant')
  489. filterset = filtersets.PrefixFilterSet
  490. table = tables.PrefixTable
  491. #
  492. # IP Ranges
  493. #
  494. class IPRangeListView(generic.ObjectListView):
  495. queryset = IPRange.objects.all()
  496. filterset = filtersets.IPRangeFilterSet
  497. filterset_form = forms.IPRangeFilterForm
  498. table = tables.IPRangeTable
  499. @register_model_view(IPRange)
  500. class IPRangeView(generic.ObjectView):
  501. queryset = IPRange.objects.all()
  502. @register_model_view(IPRange, 'ipaddresses', path='ip-addresses')
  503. class IPRangeIPAddressesView(generic.ObjectChildrenView):
  504. queryset = IPRange.objects.all()
  505. child_model = IPAddress
  506. table = tables.IPAddressTable
  507. filterset = filtersets.IPAddressFilterSet
  508. template_name = 'ipam/iprange/ip_addresses.html'
  509. tab = ViewTab(
  510. label=_('IP Addresses'),
  511. badge=lambda x: x.get_child_ips().count(),
  512. permission='ipam.view_ipaddress',
  513. weight=500
  514. )
  515. def get_children(self, request, parent):
  516. return parent.get_child_ips().restrict(request.user, 'view')
  517. @register_model_view(IPRange, 'edit')
  518. class IPRangeEditView(generic.ObjectEditView):
  519. queryset = IPRange.objects.all()
  520. form = forms.IPRangeForm
  521. @register_model_view(IPRange, 'delete')
  522. class IPRangeDeleteView(generic.ObjectDeleteView):
  523. queryset = IPRange.objects.all()
  524. class IPRangeBulkImportView(generic.BulkImportView):
  525. queryset = IPRange.objects.all()
  526. model_form = forms.IPRangeImportForm
  527. class IPRangeBulkEditView(generic.BulkEditView):
  528. queryset = IPRange.objects.all()
  529. filterset = filtersets.IPRangeFilterSet
  530. table = tables.IPRangeTable
  531. form = forms.IPRangeBulkEditForm
  532. class IPRangeBulkDeleteView(generic.BulkDeleteView):
  533. queryset = IPRange.objects.all()
  534. filterset = filtersets.IPRangeFilterSet
  535. table = tables.IPRangeTable
  536. #
  537. # IP addresses
  538. #
  539. class IPAddressListView(generic.ObjectListView):
  540. queryset = IPAddress.objects.all()
  541. filterset = filtersets.IPAddressFilterSet
  542. filterset_form = forms.IPAddressFilterForm
  543. table = tables.IPAddressTable
  544. @register_model_view(IPAddress)
  545. class IPAddressView(generic.ObjectView):
  546. queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
  547. def get_extra_context(self, request, instance):
  548. # Parent prefixes table
  549. parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  550. vrf=instance.vrf,
  551. prefix__net_contains_or_equals=str(instance.address.ip)
  552. ).prefetch_related(
  553. 'site', 'role'
  554. )
  555. parent_prefixes_table = tables.PrefixTable(
  556. list(parent_prefixes),
  557. exclude=('vrf', 'utilization'),
  558. orderable=False
  559. )
  560. # Duplicate IPs table
  561. duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter(
  562. vrf=instance.vrf,
  563. address=str(instance.address)
  564. ).exclude(
  565. pk=instance.pk
  566. ).prefetch_related(
  567. 'nat_inside'
  568. )
  569. # Exclude anycast IPs if this IP is anycast
  570. if instance.role == IPAddressRoleChoices.ROLE_ANYCAST:
  571. duplicate_ips = duplicate_ips.exclude(role=IPAddressRoleChoices.ROLE_ANYCAST)
  572. # Limit to a maximum of 10 duplicates displayed here
  573. duplicate_ips_table = tables.IPAddressTable(duplicate_ips[:10], orderable=False)
  574. return {
  575. 'parent_prefixes_table': parent_prefixes_table,
  576. 'duplicate_ips_table': duplicate_ips_table,
  577. }
  578. @register_model_view(IPAddress, 'edit')
  579. class IPAddressEditView(generic.ObjectEditView):
  580. queryset = IPAddress.objects.all()
  581. form = forms.IPAddressForm
  582. template_name = 'ipam/ipaddress_edit.html'
  583. def alter_object(self, obj, request, url_args, url_kwargs):
  584. if 'interface' in request.GET:
  585. try:
  586. obj.assigned_object = Interface.objects.get(pk=request.GET['interface'])
  587. except (ValueError, Interface.DoesNotExist):
  588. pass
  589. elif 'vminterface' in request.GET:
  590. try:
  591. obj.assigned_object = VMInterface.objects.get(pk=request.GET['vminterface'])
  592. except (ValueError, VMInterface.DoesNotExist):
  593. pass
  594. elif 'fhrpgroup' in request.GET:
  595. try:
  596. obj.assigned_object = FHRPGroup.objects.get(pk=request.GET['fhrpgroup'])
  597. except (ValueError, FHRPGroup.DoesNotExist):
  598. pass
  599. return obj
  600. # TODO: Standardize or remove this view
  601. class IPAddressAssignView(generic.ObjectView):
  602. """
  603. Search for IPAddresses to be assigned to an Interface.
  604. """
  605. queryset = IPAddress.objects.all()
  606. def dispatch(self, request, *args, **kwargs):
  607. # Redirect user if an interface has not been provided
  608. if 'interface' not in request.GET and 'vminterface' not in request.GET:
  609. return redirect('ipam:ipaddress_add')
  610. return super().dispatch(request, *args, **kwargs)
  611. def get(self, request):
  612. form = forms.IPAddressAssignForm()
  613. return render(request, 'ipam/ipaddress_assign.html', {
  614. 'form': form,
  615. 'return_url': request.GET.get('return_url', ''),
  616. })
  617. def post(self, request):
  618. form = forms.IPAddressAssignForm(request.POST)
  619. table = None
  620. if form.is_valid():
  621. addresses = self.queryset.prefetch_related('vrf', 'tenant')
  622. # Limit to 100 results
  623. addresses = filtersets.IPAddressFilterSet(request.POST, addresses).qs[:100]
  624. table = tables.IPAddressAssignTable(addresses)
  625. return render(request, 'ipam/ipaddress_assign.html', {
  626. 'form': form,
  627. 'table': table,
  628. 'return_url': request.GET.get('return_url'),
  629. })
  630. @register_model_view(IPAddress, 'delete')
  631. class IPAddressDeleteView(generic.ObjectDeleteView):
  632. queryset = IPAddress.objects.all()
  633. class IPAddressBulkCreateView(generic.BulkCreateView):
  634. queryset = IPAddress.objects.all()
  635. form = forms.IPAddressBulkCreateForm
  636. model_form = forms.IPAddressBulkAddForm
  637. pattern_target = 'address'
  638. template_name = 'ipam/ipaddress_bulk_add.html'
  639. class IPAddressBulkImportView(generic.BulkImportView):
  640. queryset = IPAddress.objects.all()
  641. model_form = forms.IPAddressImportForm
  642. class IPAddressBulkEditView(generic.BulkEditView):
  643. queryset = IPAddress.objects.prefetch_related('vrf__tenant')
  644. filterset = filtersets.IPAddressFilterSet
  645. table = tables.IPAddressTable
  646. form = forms.IPAddressBulkEditForm
  647. class IPAddressBulkDeleteView(generic.BulkDeleteView):
  648. queryset = IPAddress.objects.prefetch_related('vrf__tenant')
  649. filterset = filtersets.IPAddressFilterSet
  650. table = tables.IPAddressTable
  651. @register_model_view(IPAddress, 'related_ips', path='related-ip-addresses')
  652. class IPAddressRelatedIPsView(generic.ObjectChildrenView):
  653. queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
  654. child_model = IPAddress
  655. table = tables.IPAddressTable
  656. filterset = filtersets.IPAddressFilterSet
  657. template_name = 'ipam/ipaddress/ip_addresses.html'
  658. tab = ViewTab(
  659. label=_('Related IPs'),
  660. badge=lambda x: x.get_related_ips().count(),
  661. weight=500,
  662. hide_if_empty=True,
  663. )
  664. def get_children(self, request, parent):
  665. return parent.get_related_ips().restrict(request.user, 'view')
  666. #
  667. # VLAN groups
  668. #
  669. class VLANGroupListView(generic.ObjectListView):
  670. queryset = VLANGroup.objects.annotate(
  671. vlan_count=count_related(VLAN, 'group')
  672. )
  673. filterset = filtersets.VLANGroupFilterSet
  674. filterset_form = forms.VLANGroupFilterForm
  675. table = tables.VLANGroupTable
  676. @register_model_view(VLANGroup)
  677. class VLANGroupView(generic.ObjectView):
  678. queryset = VLANGroup.objects.all()
  679. def get_extra_context(self, request, instance):
  680. related_models = (
  681. (VLAN.objects.restrict(request.user, 'view').filter(group=instance), 'group_id'),
  682. )
  683. # TODO: Replace with embedded table
  684. vlans = VLAN.objects.restrict(request.user, 'view').filter(group=instance).prefetch_related(
  685. Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user)),
  686. 'tenant', 'site', 'role',
  687. ).order_by('vid')
  688. vlans = add_available_vlans(vlans, vlan_group=instance)
  689. vlans_table = tables.VLANTable(vlans, user=request.user, exclude=('group',))
  690. if request.user.has_perm('ipam.change_vlan') or request.user.has_perm('ipam.delete_vlan'):
  691. vlans_table.columns.show('pk')
  692. vlans_table.configure(request)
  693. return {
  694. 'related_models': related_models,
  695. 'vlans_table': vlans_table,
  696. }
  697. @register_model_view(VLANGroup, 'edit')
  698. class VLANGroupEditView(generic.ObjectEditView):
  699. queryset = VLANGroup.objects.all()
  700. form = forms.VLANGroupForm
  701. @register_model_view(VLANGroup, 'delete')
  702. class VLANGroupDeleteView(generic.ObjectDeleteView):
  703. queryset = VLANGroup.objects.all()
  704. class VLANGroupBulkImportView(generic.BulkImportView):
  705. queryset = VLANGroup.objects.all()
  706. model_form = forms.VLANGroupImportForm
  707. class VLANGroupBulkEditView(generic.BulkEditView):
  708. queryset = VLANGroup.objects.annotate(
  709. vlan_count=count_related(VLAN, 'group')
  710. )
  711. filterset = filtersets.VLANGroupFilterSet
  712. table = tables.VLANGroupTable
  713. form = forms.VLANGroupBulkEditForm
  714. class VLANGroupBulkDeleteView(generic.BulkDeleteView):
  715. queryset = VLANGroup.objects.annotate(
  716. vlan_count=count_related(VLAN, 'group')
  717. )
  718. filterset = filtersets.VLANGroupFilterSet
  719. table = tables.VLANGroupTable
  720. #
  721. # FHRP groups
  722. #
  723. class FHRPGroupListView(generic.ObjectListView):
  724. queryset = FHRPGroup.objects.annotate(
  725. member_count=count_related(FHRPGroupAssignment, 'group')
  726. )
  727. filterset = filtersets.FHRPGroupFilterSet
  728. filterset_form = forms.FHRPGroupFilterForm
  729. table = tables.FHRPGroupTable
  730. @register_model_view(FHRPGroup)
  731. class FHRPGroupView(generic.ObjectView):
  732. queryset = FHRPGroup.objects.all()
  733. def get_extra_context(self, request, instance):
  734. # Get assigned interfaces
  735. members_table = tables.FHRPGroupAssignmentTable(
  736. data=FHRPGroupAssignment.objects.restrict(request.user, 'view').filter(group=instance),
  737. orderable=False
  738. )
  739. members_table.columns.hide('group')
  740. return {
  741. 'members_table': members_table,
  742. 'member_count': FHRPGroupAssignment.objects.filter(group=instance).count(),
  743. }
  744. @register_model_view(FHRPGroup, 'edit')
  745. class FHRPGroupEditView(generic.ObjectEditView):
  746. queryset = FHRPGroup.objects.all()
  747. form = forms.FHRPGroupForm
  748. def get_return_url(self, request, obj=None):
  749. return_url = super().get_return_url(request, obj)
  750. # If we're redirecting the user to the FHRPGroupAssignment creation form,
  751. # initialize the group field with the FHRPGroup we just saved.
  752. if return_url.startswith(reverse('ipam:fhrpgroupassignment_add')):
  753. return_url += f'&group={obj.pk}'
  754. return return_url
  755. def alter_object(self, obj, request, url_args, url_kwargs):
  756. # Workaround to solve #10719. Capture the current user on the FHRPGroup instance so that
  757. # we can evaluate permissions during the creation of a new IPAddress within the form.
  758. obj._user = request.user
  759. return obj
  760. @register_model_view(FHRPGroup, 'delete')
  761. class FHRPGroupDeleteView(generic.ObjectDeleteView):
  762. queryset = FHRPGroup.objects.all()
  763. class FHRPGroupBulkImportView(generic.BulkImportView):
  764. queryset = FHRPGroup.objects.all()
  765. model_form = forms.FHRPGroupImportForm
  766. class FHRPGroupBulkEditView(generic.BulkEditView):
  767. queryset = FHRPGroup.objects.all()
  768. filterset = filtersets.FHRPGroupFilterSet
  769. table = tables.FHRPGroupTable
  770. form = forms.FHRPGroupBulkEditForm
  771. class FHRPGroupBulkDeleteView(generic.BulkDeleteView):
  772. queryset = FHRPGroup.objects.all()
  773. filterset = filtersets.FHRPGroupFilterSet
  774. table = tables.FHRPGroupTable
  775. #
  776. # FHRP group assignments
  777. #
  778. @register_model_view(FHRPGroupAssignment, 'edit')
  779. class FHRPGroupAssignmentEditView(generic.ObjectEditView):
  780. queryset = FHRPGroupAssignment.objects.all()
  781. form = forms.FHRPGroupAssignmentForm
  782. template_name = 'ipam/fhrpgroupassignment_edit.html'
  783. def alter_object(self, instance, request, args, kwargs):
  784. if not instance.pk:
  785. # Assign the interface based on URL kwargs
  786. content_type = get_object_or_404(ContentType, pk=request.GET.get('interface_type'))
  787. instance.interface = get_object_or_404(content_type.model_class(), pk=request.GET.get('interface_id'))
  788. return instance
  789. @register_model_view(FHRPGroupAssignment, 'delete')
  790. class FHRPGroupAssignmentDeleteView(generic.ObjectDeleteView):
  791. queryset = FHRPGroupAssignment.objects.all()
  792. #
  793. # VLANs
  794. #
  795. class VLANListView(generic.ObjectListView):
  796. queryset = VLAN.objects.all()
  797. filterset = filtersets.VLANFilterSet
  798. filterset_form = forms.VLANFilterForm
  799. table = tables.VLANTable
  800. @register_model_view(VLAN)
  801. class VLANView(generic.ObjectView):
  802. queryset = VLAN.objects.all()
  803. def get_extra_context(self, request, instance):
  804. prefixes = Prefix.objects.restrict(request.user, 'view').filter(vlan=instance).prefetch_related(
  805. 'vrf', 'site', 'role', 'tenant'
  806. )
  807. prefix_table = tables.PrefixTable(list(prefixes), exclude=('vlan', 'utilization'), orderable=False)
  808. return {
  809. 'prefix_table': prefix_table,
  810. }
  811. @register_model_view(VLAN, 'interfaces')
  812. class VLANInterfacesView(generic.ObjectChildrenView):
  813. queryset = VLAN.objects.all()
  814. child_model = Interface
  815. table = tables.VLANDevicesTable
  816. filterset = InterfaceFilterSet
  817. template_name = 'ipam/vlan/interfaces.html'
  818. tab = ViewTab(
  819. label=_('Device Interfaces'),
  820. badge=lambda x: x.get_interfaces().count(),
  821. permission='dcim.view_interface',
  822. weight=500
  823. )
  824. def get_children(self, request, parent):
  825. return parent.get_interfaces().restrict(request.user, 'view')
  826. @register_model_view(VLAN, 'vminterfaces', path='vm-interfaces')
  827. class VLANVMInterfacesView(generic.ObjectChildrenView):
  828. queryset = VLAN.objects.all()
  829. child_model = VMInterface
  830. table = tables.VLANVirtualMachinesTable
  831. filterset = VMInterfaceFilterSet
  832. template_name = 'ipam/vlan/vminterfaces.html'
  833. tab = ViewTab(
  834. label=_('VM Interfaces'),
  835. badge=lambda x: x.get_vminterfaces().count(),
  836. permission='virtualization.view_vminterface',
  837. weight=510
  838. )
  839. def get_children(self, request, parent):
  840. return parent.get_vminterfaces().restrict(request.user, 'view')
  841. @register_model_view(VLAN, 'edit')
  842. class VLANEditView(generic.ObjectEditView):
  843. queryset = VLAN.objects.all()
  844. form = forms.VLANForm
  845. template_name = 'ipam/vlan_edit.html'
  846. @register_model_view(VLAN, 'delete')
  847. class VLANDeleteView(generic.ObjectDeleteView):
  848. queryset = VLAN.objects.all()
  849. class VLANBulkImportView(generic.BulkImportView):
  850. queryset = VLAN.objects.all()
  851. model_form = forms.VLANImportForm
  852. class VLANBulkEditView(generic.BulkEditView):
  853. queryset = VLAN.objects.all()
  854. filterset = filtersets.VLANFilterSet
  855. table = tables.VLANTable
  856. form = forms.VLANBulkEditForm
  857. class VLANBulkDeleteView(generic.BulkDeleteView):
  858. queryset = VLAN.objects.all()
  859. filterset = filtersets.VLANFilterSet
  860. table = tables.VLANTable
  861. #
  862. # Service templates
  863. #
  864. class ServiceTemplateListView(generic.ObjectListView):
  865. queryset = ServiceTemplate.objects.all()
  866. filterset = filtersets.ServiceTemplateFilterSet
  867. filterset_form = forms.ServiceTemplateFilterForm
  868. table = tables.ServiceTemplateTable
  869. @register_model_view(ServiceTemplate)
  870. class ServiceTemplateView(generic.ObjectView):
  871. queryset = ServiceTemplate.objects.all()
  872. @register_model_view(ServiceTemplate, 'edit')
  873. class ServiceTemplateEditView(generic.ObjectEditView):
  874. queryset = ServiceTemplate.objects.all()
  875. form = forms.ServiceTemplateForm
  876. @register_model_view(ServiceTemplate, 'delete')
  877. class ServiceTemplateDeleteView(generic.ObjectDeleteView):
  878. queryset = ServiceTemplate.objects.all()
  879. class ServiceTemplateBulkImportView(generic.BulkImportView):
  880. queryset = ServiceTemplate.objects.all()
  881. model_form = forms.ServiceTemplateImportForm
  882. class ServiceTemplateBulkEditView(generic.BulkEditView):
  883. queryset = ServiceTemplate.objects.all()
  884. filterset = filtersets.ServiceTemplateFilterSet
  885. table = tables.ServiceTemplateTable
  886. form = forms.ServiceTemplateBulkEditForm
  887. class ServiceTemplateBulkDeleteView(generic.BulkDeleteView):
  888. queryset = ServiceTemplate.objects.all()
  889. filterset = filtersets.ServiceTemplateFilterSet
  890. table = tables.ServiceTemplateTable
  891. #
  892. # Services
  893. #
  894. class ServiceListView(generic.ObjectListView):
  895. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  896. filterset = filtersets.ServiceFilterSet
  897. filterset_form = forms.ServiceFilterForm
  898. table = tables.ServiceTable
  899. @register_model_view(Service)
  900. class ServiceView(generic.ObjectView):
  901. queryset = Service.objects.all()
  902. class ServiceCreateView(generic.ObjectEditView):
  903. queryset = Service.objects.all()
  904. form = forms.ServiceCreateForm
  905. template_name = 'ipam/service_create.html'
  906. @register_model_view(Service, 'edit')
  907. class ServiceEditView(generic.ObjectEditView):
  908. queryset = Service.objects.all()
  909. form = forms.ServiceForm
  910. template_name = 'ipam/service_edit.html'
  911. @register_model_view(Service, 'delete')
  912. class ServiceDeleteView(generic.ObjectDeleteView):
  913. queryset = Service.objects.all()
  914. class ServiceBulkImportView(generic.BulkImportView):
  915. queryset = Service.objects.all()
  916. model_form = forms.ServiceImportForm
  917. class ServiceBulkEditView(generic.BulkEditView):
  918. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  919. filterset = filtersets.ServiceFilterSet
  920. table = tables.ServiceTable
  921. form = forms.ServiceBulkEditForm
  922. class ServiceBulkDeleteView(generic.BulkDeleteView):
  923. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  924. filterset = filtersets.ServiceFilterSet
  925. table = tables.ServiceTable
  926. # L2VPN
  927. class L2VPNListView(generic.ObjectListView):
  928. queryset = L2VPN.objects.all()
  929. table = L2VPNTable
  930. filterset = filtersets.L2VPNFilterSet
  931. filterset_form = forms.L2VPNFilterForm
  932. @register_model_view(L2VPN)
  933. class L2VPNView(generic.ObjectView):
  934. queryset = L2VPN.objects.all()
  935. def get_extra_context(self, request, instance):
  936. import_targets_table = tables.RouteTargetTable(
  937. instance.import_targets.prefetch_related('tenant'),
  938. orderable=False
  939. )
  940. export_targets_table = tables.RouteTargetTable(
  941. instance.export_targets.prefetch_related('tenant'),
  942. orderable=False
  943. )
  944. return {
  945. 'import_targets_table': import_targets_table,
  946. 'export_targets_table': export_targets_table,
  947. }
  948. @register_model_view(L2VPN, 'edit')
  949. class L2VPNEditView(generic.ObjectEditView):
  950. queryset = L2VPN.objects.all()
  951. form = forms.L2VPNForm
  952. @register_model_view(L2VPN, 'delete')
  953. class L2VPNDeleteView(generic.ObjectDeleteView):
  954. queryset = L2VPN.objects.all()
  955. class L2VPNBulkImportView(generic.BulkImportView):
  956. queryset = L2VPN.objects.all()
  957. model_form = forms.L2VPNImportForm
  958. class L2VPNBulkEditView(generic.BulkEditView):
  959. queryset = L2VPN.objects.all()
  960. filterset = filtersets.L2VPNFilterSet
  961. table = tables.L2VPNTable
  962. form = forms.L2VPNBulkEditForm
  963. class L2VPNBulkDeleteView(generic.BulkDeleteView):
  964. queryset = L2VPN.objects.all()
  965. filterset = filtersets.L2VPNFilterSet
  966. table = tables.L2VPNTable
  967. #
  968. # L2VPN terminations
  969. #
  970. class L2VPNTerminationListView(generic.ObjectListView):
  971. queryset = L2VPNTermination.objects.all()
  972. table = L2VPNTerminationTable
  973. filterset = filtersets.L2VPNTerminationFilterSet
  974. filterset_form = forms.L2VPNTerminationFilterForm
  975. @register_model_view(L2VPNTermination)
  976. class L2VPNTerminationView(generic.ObjectView):
  977. queryset = L2VPNTermination.objects.all()
  978. @register_model_view(L2VPNTermination, 'edit')
  979. class L2VPNTerminationEditView(generic.ObjectEditView):
  980. queryset = L2VPNTermination.objects.all()
  981. form = forms.L2VPNTerminationForm
  982. template_name = 'ipam/l2vpntermination_edit.html'
  983. @register_model_view(L2VPNTermination, 'delete')
  984. class L2VPNTerminationDeleteView(generic.ObjectDeleteView):
  985. queryset = L2VPNTermination.objects.all()
  986. class L2VPNTerminationBulkImportView(generic.BulkImportView):
  987. queryset = L2VPNTermination.objects.all()
  988. model_form = forms.L2VPNTerminationImportForm
  989. class L2VPNTerminationBulkEditView(generic.BulkEditView):
  990. queryset = L2VPNTermination.objects.all()
  991. filterset = filtersets.L2VPNTerminationFilterSet
  992. table = tables.L2VPNTerminationTable
  993. form = forms.L2VPNTerminationBulkEditForm
  994. class L2VPNTerminationBulkDeleteView(generic.BulkDeleteView):
  995. queryset = L2VPNTermination.objects.all()
  996. filterset = filtersets.L2VPNTerminationFilterSet
  997. table = tables.L2VPNTerminationTable