nautobot 2.4.3__py3-none-any.whl → 2.4.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (198) hide show
  1. nautobot/__init__.py +19 -3
  2. nautobot/apps/filters.py +2 -0
  3. nautobot/circuits/filters.py +1 -1
  4. nautobot/circuits/tests/test_models.py +5 -3
  5. nautobot/cloud/filters.py +3 -6
  6. nautobot/cloud/tests/test_filters.py +21 -0
  7. nautobot/core/admin.py +2 -0
  8. nautobot/core/celery/__init__.py +5 -3
  9. nautobot/core/jobs/__init__.py +5 -3
  10. nautobot/core/management/commands/generate_performance_test_endpoints.py +9 -6
  11. nautobot/core/models/utils.py +6 -1
  12. nautobot/core/templates/inc/javascript.html +1 -0
  13. nautobot/core/templatetags/ui_framework.py +20 -4
  14. nautobot/core/testing/__init__.py +2 -0
  15. nautobot/core/testing/forms.py +1 -1
  16. nautobot/core/testing/mixins.py +9 -0
  17. nautobot/core/tests/test_api.py +1 -1
  18. nautobot/core/tests/test_graphql.py +3 -3
  19. nautobot/core/tests/test_jobs.py +30 -28
  20. nautobot/core/ui/object_detail.py +1 -1
  21. nautobot/dcim/api/serializers.py +36 -0
  22. nautobot/dcim/api/views.py +1 -1
  23. nautobot/dcim/elevations.py +17 -4
  24. nautobot/dcim/factory.py +9 -1
  25. nautobot/dcim/filters/__init__.py +27 -1
  26. nautobot/dcim/forms.py +13 -1
  27. nautobot/dcim/models/devices.py +11 -5
  28. nautobot/dcim/signals.py +26 -0
  29. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -62
  30. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +6 -0
  31. nautobot/dcim/tests/test_api.py +176 -0
  32. nautobot/dcim/tests/test_filters.py +56 -3
  33. nautobot/dcim/tests/test_jobs.py +4 -6
  34. nautobot/dcim/tests/test_models.py +40 -0
  35. nautobot/dcim/views.py +24 -14
  36. nautobot/extras/api/mixins.py +1 -1
  37. nautobot/extras/api/views.py +2 -2
  38. nautobot/extras/choices.py +8 -3
  39. nautobot/extras/filters/__init__.py +4 -0
  40. nautobot/extras/jobs.py +181 -103
  41. nautobot/extras/management/utils.py +13 -2
  42. nautobot/extras/models/datasources.py +11 -4
  43. nautobot/extras/models/jobs.py +20 -17
  44. nautobot/extras/plugins/__init__.py +26 -1
  45. nautobot/extras/tables.py +25 -29
  46. nautobot/extras/templates/extras/inc/jobresult.html +12 -13
  47. nautobot/extras/templates/extras/objectchange.html +28 -12
  48. nautobot/extras/test_jobs/atomic_transaction.py +6 -6
  49. nautobot/extras/test_jobs/fail.py +75 -1
  50. nautobot/extras/tests/test_api.py +17 -16
  51. nautobot/extras/tests/test_datasources.py +64 -54
  52. nautobot/extras/tests/test_filters.py +2 -0
  53. nautobot/extras/tests/test_jobs.py +69 -62
  54. nautobot/extras/tests/test_models.py +1 -1
  55. nautobot/extras/tests/test_plugins.py +32 -1
  56. nautobot/extras/tests/test_relationships.py +5 -5
  57. nautobot/extras/tests/test_views.py +12 -2
  58. nautobot/extras/views.py +10 -1
  59. nautobot/ipam/api/serializers.py +7 -8
  60. nautobot/ipam/api/views.py +2 -2
  61. nautobot/ipam/factory.py +27 -8
  62. nautobot/ipam/filters.py +67 -29
  63. nautobot/ipam/formfields.py +51 -0
  64. nautobot/ipam/forms.py +28 -1
  65. nautobot/ipam/migrations/0051_added_optional_vrf_relationship_to_vdc.py +41 -0
  66. nautobot/ipam/models.py +63 -5
  67. nautobot/ipam/querysets.py +6 -0
  68. nautobot/ipam/tables.py +21 -7
  69. nautobot/ipam/templates/ipam/rir.html +1 -43
  70. nautobot/ipam/tests/test_api.py +107 -66
  71. nautobot/ipam/tests/test_filters.py +145 -5
  72. nautobot/ipam/tests/test_models.py +16 -0
  73. nautobot/ipam/tests/test_views.py +15 -2
  74. nautobot/ipam/urls.py +1 -21
  75. nautobot/ipam/views.py +24 -41
  76. nautobot/project-static/css/base.css +11 -0
  77. nautobot/project-static/css/dark.css +2 -1
  78. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +62 -0
  79. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +43 -5
  80. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +35 -0
  81. nautobot/project-static/docs/development/apps/api/configuration-view.html +0 -3
  82. nautobot/project-static/docs/development/apps/api/models/graphql.html +0 -4
  83. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +94 -1
  84. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +0 -3
  85. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +0 -3
  86. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +0 -3
  87. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +0 -3
  88. nautobot/project-static/docs/development/apps/api/prometheus.html +0 -3
  89. nautobot/project-static/docs/development/apps/api/testing.html +0 -6
  90. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +0 -3
  91. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +0 -3
  92. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +0 -3
  93. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +0 -3
  94. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +1 -7
  95. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +0 -7
  96. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +0 -4
  97. nautobot/project-static/docs/development/apps/api/views/notes.html +0 -3
  98. nautobot/project-static/docs/development/apps/index.html +2 -35
  99. nautobot/project-static/docs/development/apps/migration/code-updates.html +1 -1
  100. nautobot/project-static/docs/development/core/application-registry.html +0 -6
  101. nautobot/project-static/docs/development/core/best-practices.html +0 -27
  102. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +58 -4
  103. nautobot/project-static/docs/development/core/getting-started.html +12 -16
  104. nautobot/project-static/docs/development/core/homepage.html +0 -3
  105. nautobot/project-static/docs/development/core/style-guide.html +0 -5
  106. nautobot/project-static/docs/development/core/templates.html +0 -3
  107. nautobot/project-static/docs/development/core/testing.html +0 -9
  108. nautobot/project-static/docs/development/jobs/index.html +30 -43
  109. nautobot/project-static/docs/objects.inv +0 -0
  110. nautobot/project-static/docs/overview/application_stack.html +0 -18
  111. nautobot/project-static/docs/release-notes/version-2.4.html +374 -0
  112. nautobot/project-static/docs/requirements.txt +2 -2
  113. nautobot/project-static/docs/search/search_index.json +1 -1
  114. nautobot/project-static/docs/sitemap.xml +290 -290
  115. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  116. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +0 -10
  117. nautobot/project-static/docs/user-guide/administration/guides/docker.html +0 -15
  118. nautobot/project-static/docs/user-guide/administration/installation/index.html +0 -16
  119. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +1 -4
  120. nautobot/project-static/docs/user-guide/administration/installation/services.html +0 -11
  121. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +3 -3
  122. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +5 -35
  123. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-location-changes.yaml +1 -1
  124. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +1 -1
  125. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +0 -4
  126. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +0 -3
  127. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +0 -4
  128. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +0 -4
  129. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +0 -4
  130. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +0 -4
  131. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +0 -4
  132. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +0 -4
  133. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +0 -3
  134. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +0 -4
  135. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +0 -4
  136. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +0 -4
  137. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +1 -17
  138. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +0 -3
  139. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +0 -4
  140. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +0 -4
  141. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +0 -3
  142. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +1 -7
  143. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +0 -4
  144. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +0 -4
  145. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +0 -4
  146. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +0 -4
  147. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +0 -4
  148. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +0 -4
  149. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +0 -4
  150. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +0 -6
  151. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +0 -3
  152. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +0 -4
  153. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +0 -4
  154. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +0 -8
  155. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +3 -3
  156. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +0 -6
  157. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +0 -3
  158. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +3 -15
  159. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +0 -26
  160. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +0 -8
  161. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +0 -3
  162. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +0 -8
  163. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +0 -7
  164. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +0 -3
  165. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +0 -3
  166. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +0 -14
  167. nautobot/project-static/docs/user-guide/platform-functionality/note.html +0 -3
  168. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +1 -10
  169. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +0 -3
  170. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +0 -14
  171. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +0 -19
  172. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +3 -9
  173. nautobot/project-static/docs/user-guide/platform-functionality/status.html +0 -8
  174. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +0 -4
  175. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +1 -13
  176. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +0 -5
  177. nautobot/project-static/js/editor.js +292 -0
  178. nautobot/project-static/monaco-editor-0.52.2/README.md +81 -0
  179. nautobot/project-static/monaco-editor-0.52.2/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
  180. nautobot/project-static/monaco-editor-0.52.2/vs/base/worker/workerMain.js +31 -0
  181. nautobot/project-static/monaco-editor-0.52.2/vs/basic-languages/xml/xml.js +10 -0
  182. nautobot/project-static/monaco-editor-0.52.2/vs/basic-languages/yaml/yaml.js +10 -0
  183. nautobot/project-static/monaco-editor-0.52.2/vs/editor/editor.main.css +8 -0
  184. nautobot/project-static/monaco-editor-0.52.2/vs/editor/editor.main.js +798 -0
  185. nautobot/project-static/monaco-editor-0.52.2/vs/language/json/jsonMode.js +19 -0
  186. nautobot/project-static/monaco-editor-0.52.2/vs/language/json/jsonWorker.js +42 -0
  187. nautobot/project-static/monaco-editor-0.52.2/vs/loader.js +11 -0
  188. nautobot/tenancy/filters/__init__.py +3 -5
  189. nautobot/tenancy/tests/test_filters.py +10 -0
  190. nautobot/virtualization/views.py +0 -1
  191. nautobot/wireless/tables.py +9 -4
  192. nautobot/wireless/tests/test_api.py +0 -9
  193. {nautobot-2.4.3.dist-info → nautobot-2.4.5.dist-info}/METADATA +4 -4
  194. {nautobot-2.4.3.dist-info → nautobot-2.4.5.dist-info}/RECORD +198 -186
  195. {nautobot-2.4.3.dist-info → nautobot-2.4.5.dist-info}/LICENSE.txt +0 -0
  196. {nautobot-2.4.3.dist-info → nautobot-2.4.5.dist-info}/NOTICE +0 -0
  197. {nautobot-2.4.3.dist-info → nautobot-2.4.5.dist-info}/WHEEL +0 -0
  198. {nautobot-2.4.3.dist-info → nautobot-2.4.5.dist-info}/entry_points.txt +0 -0
@@ -7487,6 +7487,15 @@
7487
7487
  </span>
7488
7488
  </a>
7489
7489
 
7490
+ </li>
7491
+
7492
+ <li class="md-nav__item">
7493
+ <a href="#nautobot.apps.filters.PrefixFilter" class="md-nav__link">
7494
+ <span class="md-ellipsis">
7495
+ PrefixFilter
7496
+ </span>
7497
+ </a>
7498
+
7490
7499
  </li>
7491
7500
 
7492
7501
  <li class="md-nav__item">
@@ -9724,6 +9733,15 @@
9724
9733
  </span>
9725
9734
  </a>
9726
9735
 
9736
+ </li>
9737
+
9738
+ <li class="md-nav__item">
9739
+ <a href="#nautobot.apps.filters.PrefixFilter" class="md-nav__link">
9740
+ <span class="md-ellipsis">
9741
+ PrefixFilter
9742
+ </span>
9743
+ </a>
9744
+
9727
9745
  </li>
9728
9746
 
9729
9747
  <li class="md-nav__item">
@@ -10755,6 +10773,50 @@ are needed.</p>
10755
10773
 
10756
10774
 
10757
10775
 
10776
+ </div>
10777
+
10778
+ </div>
10779
+
10780
+ </div>
10781
+
10782
+ <div class="doc doc-object doc-class">
10783
+
10784
+
10785
+
10786
+ <h2 id="nautobot.apps.filters.PrefixFilter" class="doc doc-heading">
10787
+ <code>nautobot.apps.filters.PrefixFilter</code>
10788
+
10789
+
10790
+ <a href="#nautobot.apps.filters.PrefixFilter" class="headerlink" title="Permanent link">&para;</a></h2>
10791
+
10792
+
10793
+ <div class="doc doc-contents ">
10794
+ <p class="doc doc-class-bases">
10795
+ Bases: <code><a class="autorefs autorefs-internal" title="nautobot.core.filters.NaturalKeyOrPKMultipleChoiceFilter" href="#nautobot.apps.filters.NaturalKeyOrPKMultipleChoiceFilter">NaturalKeyOrPKMultipleChoiceFilter</a></code></p>
10796
+
10797
+
10798
+ <p>Filter that supports filtering a foreign key to Prefix by either its PK or by a literal <code>prefix</code> string.</p>
10799
+
10800
+
10801
+
10802
+
10803
+
10804
+
10805
+
10806
+
10807
+
10808
+ <div class="doc doc-children">
10809
+
10810
+
10811
+
10812
+
10813
+
10814
+
10815
+
10816
+
10817
+
10818
+
10819
+
10758
10820
  </div>
10759
10821
 
10760
10822
  </div>
@@ -7419,6 +7419,15 @@
7419
7419
  </span>
7420
7420
  </a>
7421
7421
 
7422
+ </li>
7423
+
7424
+ <li class="md-nav__item">
7425
+ <a href="#nautobot.apps.jobs.BaseJob.fail" class="md-nav__link">
7426
+ <span class="md-ellipsis">
7427
+ fail
7428
+ </span>
7429
+ </a>
7430
+
7422
7431
  </li>
7423
7432
 
7424
7433
  <li class="md-nav__item">
@@ -9776,6 +9785,15 @@
9776
9785
  </span>
9777
9786
  </a>
9778
9787
 
9788
+ </li>
9789
+
9790
+ <li class="md-nav__item">
9791
+ <a href="#nautobot.apps.jobs.BaseJob.fail" class="md-nav__link">
9792
+ <span class="md-ellipsis">
9793
+ fail
9794
+ </span>
9795
+ </a>
9796
+
9779
9797
  </li>
9780
9798
 
9781
9799
  <li class="md-nav__item">
@@ -10624,11 +10642,13 @@ during a approval review workflow.</p>
10624
10642
  <tbody>
10625
10643
  <tr class="doc-section-item">
10626
10644
  <td>
10627
- <code>None</code>
10645
+ <code>Any</code>
10628
10646
  </td>
10629
10647
  <td>
10630
10648
  <div class="doc-md-description">
10631
- <p>The return value of this handler is ignored.</p>
10649
+ <p>The return value of this handler is ignored normally, <strong>except</strong> if <code>self.fail()</code> is called herein,
10650
+ in which case the return value will be used as the overall JobResult return value
10651
+ since <code>self.run()</code> will <strong>not</strong> be called in such a case.</p>
10632
10652
  </div>
10633
10653
  </td>
10634
10654
  </tr>
@@ -10835,6 +10855,23 @@ path would consider this a failure of the job execution, as described in <code>n
10835
10855
  <div class="doc doc-object doc-function">
10836
10856
 
10837
10857
 
10858
+ <h3 id="nautobot.apps.jobs.BaseJob.fail" class="doc doc-heading">
10859
+ <code class="highlight language-python"><span class="n">fail</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></code>
10860
+
10861
+ <a href="#nautobot.apps.jobs.BaseJob.fail" class="headerlink" title="Permanent link">&para;</a></h3>
10862
+
10863
+
10864
+ <div class="doc doc-contents ">
10865
+
10866
+ <p>Mark this job as failed without immediately raising an exception and aborting.</p>
10867
+
10868
+ </div>
10869
+
10870
+ </div>
10871
+
10872
+ <div class="doc doc-object doc-function">
10873
+
10874
+
10838
10875
  <h3 id="nautobot.apps.jobs.BaseJob.file_path" class="doc doc-heading">
10839
10876
  <code class="highlight language-python"><span class="n">file_path</span><span class="p">()</span></code>
10840
10877
 
@@ -10914,11 +10951,12 @@ path would consider this a failure of the job execution, as described in <code>n
10914
10951
  <code>exc</code>
10915
10952
  </td>
10916
10953
  <td>
10917
- <code>Exception</code>
10954
+ <code>Any</code>
10918
10955
  </td>
10919
10956
  <td>
10920
10957
  <div class="doc-md-description">
10921
- <p>The exception raised by the task.</p>
10958
+ <p>Exception raised by the task (if any) <strong>or</strong> return value from the task, if it failed cleanly,
10959
+ such as if the Job called <code>self.fail()</code> rather than raising an exception.</p>
10922
10960
  </div>
10923
10961
  </td>
10924
10962
  <td>
@@ -10982,7 +11020,7 @@ path would consider this a failure of the job execution, as described in <code>n
10982
11020
  </td>
10983
11021
  <td>
10984
11022
  <div class="doc-md-description">
10985
- <p>Exception information.</p>
11023
+ <p>Exception information, or None.</p>
10986
11024
  </div>
10987
11025
  </td>
10988
11026
  <td>
@@ -8238,6 +8238,15 @@
8238
8238
  </span>
8239
8239
  </a>
8240
8240
 
8241
+ </li>
8242
+
8243
+ <li class="md-nav__item">
8244
+ <a href="#nautobot.apps.testing.NautobotTestCaseMixin.assertJobResultStatus" class="md-nav__link">
8245
+ <span class="md-ellipsis">
8246
+ assertJobResultStatus
8247
+ </span>
8248
+ </a>
8249
+
8241
8250
  </li>
8242
8251
 
8243
8252
  <li class="md-nav__item">
@@ -11423,6 +11432,15 @@
11423
11432
  </span>
11424
11433
  </a>
11425
11434
 
11435
+ </li>
11436
+
11437
+ <li class="md-nav__item">
11438
+ <a href="#nautobot.apps.testing.NautobotTestCaseMixin.assertJobResultStatus" class="md-nav__link">
11439
+ <span class="md-ellipsis">
11440
+ assertJobResultStatus
11441
+ </span>
11442
+ </a>
11443
+
11426
11444
  </li>
11427
11445
 
11428
11446
  <li class="md-nav__item">
@@ -14322,6 +14340,23 @@ in the dictionary.</p>
14322
14340
  <div class="doc doc-object doc-function">
14323
14341
 
14324
14342
 
14343
+ <h3 id="nautobot.apps.testing.NautobotTestCaseMixin.assertJobResultStatus" class="doc doc-heading">
14344
+ <code class="highlight language-python"><span class="n">assertJobResultStatus</span><span class="p">(</span><span class="n">job_result</span><span class="p">,</span> <span class="n">expected_status</span><span class="o">=</span><span class="n">JobResultStatusChoices</span><span class="o">.</span><span class="n">STATUS_SUCCESS</span><span class="p">)</span></code>
14345
+
14346
+ <a href="#nautobot.apps.testing.NautobotTestCaseMixin.assertJobResultStatus" class="headerlink" title="Permanent link">&para;</a></h3>
14347
+
14348
+
14349
+ <div class="doc doc-contents ">
14350
+
14351
+ <p>Assert that the given job_result has the expected_status, or print the job logs to aid in debugging.</p>
14352
+
14353
+ </div>
14354
+
14355
+ </div>
14356
+
14357
+ <div class="doc doc-object doc-function">
14358
+
14359
+
14325
14360
  <h3 id="nautobot.apps.testing.NautobotTestCaseMixin.assertQuerysetEqualAndNotEmpty" class="doc doc-heading">
14326
14361
  <code class="highlight language-python"><span class="n">assertQuerysetEqualAndNotEmpty</span><span class="p">(</span><span class="n">qs</span><span class="p">,</span> <span class="n">values</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></code>
14327
14362
 
@@ -9122,9 +9122,6 @@
9122
9122
 
9123
9123
 
9124
9124
  <h1 id="adding-links-to-the-installed-apps-view">Adding Links to the Installed Apps View<a class="headerlink" href="#adding-links-to-the-installed-apps-view" title="Permanent link">&para;</a></h1>
9125
- <details class="version-added">
9126
- <summary>Added in version 1.2.0</summary>
9127
- </details>
9128
9125
  <p>It's common for many apps to provide an "app configuration" <a href="views/index.html">view</a> used for interactive configuration of aspects of the app that don't necessarily need to be managed by a system administrator via <code>PLUGINS_CONFIG</code>. The <code>NautobotAppConfig</code> setting of <code>config_view_name</code> lets you provide the URL pattern name defined for this view, which will then be accessible via a button on the <strong>Apps -&gt; Installed Apps</strong> UI view.</p>
9129
9126
  <p>For example, if the <code>animal_sounds</code> app provides a configuration view, which is set up in <code>urls.py</code> as follows:</p>
9130
9127
  <div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1"># urls.py</span>
@@ -9245,10 +9245,6 @@
9245
9245
  <a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
9246
9246
  </code></pre></div>
9247
9247
  <h2 id="creating-your-own-graphql-type-object">Creating Your Own GraphQL Type Object<a class="headerlink" href="#creating-your-own-graphql-type-object" title="Permanent link">&para;</a></h2>
9248
- <details class="version-changed">
9249
- <summary>Changed in version 1.6.2</summary>
9250
- <p>A new base class was introduced for Nautobot GraphQL object types: <code>nautobot.core.graphql.types.OptimizedNautobotObjectType</code>. This class inherits from <code>graphene_django_optimizer.OptimizedDjangoObjectType</code> and adds generic Nautobot specific functionality.</p>
9251
- </details>
9252
9248
  <p>In some cases, such as when a model is using Generic Foreign Keys, or when a model has constructed fields that should also be reflected in GraphQL, the default GraphQL type definition generated by the <code>@extras_features</code> decorator may not work as the developer intends, and it will be preferable to provide custom GraphQL types.</p>
9253
9249
  <p>By default, Nautobot looks for custom GraphQL types in an iterable named <code>graphql_types</code> within a <code>graphql/types.py</code> file. (This can be overridden by setting <code>graphql_types</code> to a custom value on the app's <code>NautobotAppConfig</code>.) Each type defined in this way must be a class inheriting from <code>graphene_django.DjangoObjectType</code>, <code>graphene_django_optimizer.OptimizedDjangoObjectType</code>, or <code>nautobot.core.graphql.types.OptimizedNautobotObjectType</code> and must follow the <a href="https://docs.graphene-python.org/projects/django/en/latest/queries/">standards defined by <code>graphene-django</code></a>.</p>
9254
9250
  <p>Nautobot uses a library called <a href="https://github.com/tfoxy/graphene-django-optimizer"><code>graphene-django-optimizer</code></a> to decrease the time queries take to process. By inheriting from <code>graphene_django_optimizer</code> type classes are automatically optimized.</p>
@@ -6534,6 +6534,17 @@
6534
6534
 
6535
6535
 
6536
6536
 
6537
+ <label class="md-nav__link md-nav__link--active" for="__toc">
6538
+
6539
+
6540
+ <span class="md-ellipsis">
6541
+ Custom Validators
6542
+ </span>
6543
+
6544
+
6545
+ <span class="md-nav__icon md-icon"></span>
6546
+ </label>
6547
+
6537
6548
  <a href="custom-validators.html" class="md-nav__link md-nav__link--active">
6538
6549
 
6539
6550
 
@@ -6544,6 +6555,34 @@
6544
6555
 
6545
6556
  </a>
6546
6557
 
6558
+
6559
+
6560
+ <nav class="md-nav md-nav--secondary" aria-label="Table of contents">
6561
+
6562
+
6563
+
6564
+
6565
+
6566
+
6567
+ <label class="md-nav__title" for="__toc">
6568
+ <span class="md-nav__icon md-icon"></span>
6569
+ Table of contents
6570
+ </label>
6571
+ <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
6572
+
6573
+ <li class="md-nav__item">
6574
+ <a href="#user-context" class="md-nav__link">
6575
+ <span class="md-ellipsis">
6576
+ User Context
6577
+ </span>
6578
+ </a>
6579
+
6580
+ </li>
6581
+
6582
+ </ul>
6583
+
6584
+ </nav>
6585
+
6547
6586
  </li>
6548
6587
 
6549
6588
 
@@ -9105,6 +9144,23 @@
9105
9144
 
9106
9145
 
9107
9146
 
9147
+ <label class="md-nav__title" for="__toc">
9148
+ <span class="md-nav__icon md-icon"></span>
9149
+ Table of contents
9150
+ </label>
9151
+ <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
9152
+
9153
+ <li class="md-nav__item">
9154
+ <a href="#user-context" class="md-nav__link">
9155
+ <span class="md-ellipsis">
9156
+ User Context
9157
+ </span>
9158
+ </a>
9159
+
9160
+ </li>
9161
+
9162
+ </ul>
9163
+
9108
9164
  </nav>
9109
9165
  </div>
9110
9166
  </div>
@@ -9124,7 +9180,7 @@
9124
9180
  <h1 id="implementing-custom-validators">Implementing Custom Validators<a class="headerlink" href="#implementing-custom-validators" title="Permanent link">&para;</a></h1>
9125
9181
  <p>Apps can register custom validator classes which implement model validation logic to be executed during a model's <code>clean()</code> method. Like template extensions, custom validators are registered to a single model and offer a method which app authors override to implement their validation logic. This is accomplished by subclassing <code>CustomValidator</code> and implementing the <code>clean()</code> method.</p>
9126
9182
  <p>App authors must raise <code>django.core.exceptions.ValidationError</code> within the <code>clean()</code> method to trigger validation error messages which are propagated to the user and prevent saving of the model instance. A convenience method <code>validation_error()</code> may be used to simplify this process. Raising a <code>ValidationError</code> is no different than vanilla Django, and the convenience method will simply pass the provided message through to the exception.</p>
9127
- <p>When a CustomValidator is instantiated, the model instance is assigned to context dictionary using the <code>object</code> key, much like TemplateExtension. E.g. <code>self.context['object']</code>.</p>
9183
+ <p>When a CustomValidator is instantiated, the model instance is assigned to context dictionary using the <code>object</code> key, much like TemplateExtension. E.g. <code>self.context['object']</code>. The context is also populated with the current request user object. E.g. <code>self.context['user']</code>.</p>
9128
9184
  <p>Declared subclasses should be gathered into a list or tuple for integration with Nautobot. By default, Nautobot looks for an iterable named <code>custom_validators</code> within a <code>custom_validators.py</code> file. (This can be overridden by setting <code>custom_validators</code> to a custom value on the app's <code>NautobotAppConfig</code>.) An example is below.</p>
9129
9185
  <div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1"># custom_validators.py</span>
9130
9186
  <a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="kn">from</span> <span class="nn">nautobot.apps.models</span> <span class="kn">import</span> <span class="n">CustomValidator</span>
@@ -9145,6 +9201,43 @@
9145
9201
  <a id="__codelineno-0-17" name="__codelineno-0-17" href="#__codelineno-0-17"></a>
9146
9202
  <a id="__codelineno-0-18" name="__codelineno-0-18" href="#__codelineno-0-18"></a><span class="n">custom_validators</span> <span class="o">=</span> <span class="p">[</span><span class="n">LocationValidator</span><span class="p">]</span>
9147
9203
  </code></pre></div>
9204
+ <h2 id="user-context">User Context<a class="headerlink" href="#user-context" title="Permanent link">&para;</a></h2>
9205
+ <details class="version-added">
9206
+ <summary>Added in version 2.4.4</summary>
9207
+ </details>
9208
+ <p>Custom validators have access to the current user via <code>self.context['user']</code> whenever the custom validator is invoked within a web request context. This is true for any Web UI, REST API request, Job execution, and anytime the <code>web_request_context</code> context manager is used in <code>nbshell</code> or a out of band script. In the event a custom validator is run outside of a web request context, <code>self.context['user']</code> will be populated with an instance of <code>AnonymousUser</code> from <code>django.contrib.auth</code>. This allows a custom validator author to write code that is durable to cases where a real user is not available.</p>
9209
+ <p>With the user object, you can inspect the groups and permissions that the user has, allowing more granular access related validation.</p>
9210
+ <p>This example shows a custom validator that only allows users in the group "Tenant Managers" to change the tenant of a location:</p>
9211
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="c1"># custom_validators.py</span>
9212
+ <a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="kn">from</span> <span class="nn">nautobot.apps.models</span> <span class="kn">import</span> <span class="n">CustomValidator</span>
9213
+ <a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>
9214
+ <a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a>
9215
+ <a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="k">class</span> <span class="nc">LocationTenantValidator</span><span class="p">(</span><span class="n">CustomValidator</span><span class="p">):</span>
9216
+ <a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Custom validator for Locations to enforce that only some users can update the Tenant.&quot;&quot;&quot;</span>
9217
+ <a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a>
9218
+ <a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a> <span class="n">model</span> <span class="o">=</span> <span class="s1">&#39;dcim.location&#39;</span>
9219
+ <a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a>
9220
+ <a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
9221
+ <a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a> <span class="n">new_object_state</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s2">&quot;object&quot;</span><span class="p">]</span>
9222
+ <a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">new_object_state</span><span class="o">.</span><span class="n">present_in_database</span><span class="p">:</span>
9223
+ <a id="__codelineno-1-13" name="__codelineno-1-13" href="#__codelineno-1-13"></a> <span class="c1"># This is a brand new Location, so skip the rest of the checks here</span>
9224
+ <a id="__codelineno-1-14" name="__codelineno-1-14" href="#__codelineno-1-14"></a> <span class="k">return</span>
9225
+ <a id="__codelineno-1-15" name="__codelineno-1-15" href="#__codelineno-1-15"></a>
9226
+ <a id="__codelineno-1-16" name="__codelineno-1-16" href="#__codelineno-1-16"></a> <span class="c1"># Get a copy of the object as it currently exists in the database</span>
9227
+ <a id="__codelineno-1-17" name="__codelineno-1-17" href="#__codelineno-1-17"></a> <span class="n">current_object_state</span> <span class="o">=</span> <span class="n">new_object_state</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="n">new_object_state</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
9228
+ <a id="__codelineno-1-18" name="__codelineno-1-18" href="#__codelineno-1-18"></a>
9229
+ <a id="__codelineno-1-19" name="__codelineno-1-19" href="#__codelineno-1-19"></a> <span class="c1"># Compare the tenant values between the two states</span>
9230
+ <a id="__codelineno-1-20" name="__codelineno-1-20" href="#__codelineno-1-20"></a> <span class="k">if</span> <span class="n">new_object_state</span><span class="o">.</span><span class="n">tenant</span> <span class="o">!=</span> <span class="n">current_object_state</span><span class="o">.</span><span class="n">tenant</span><span class="p">:</span>
9231
+ <a id="__codelineno-1-21" name="__codelineno-1-21" href="#__codelineno-1-21"></a>
9232
+ <a id="__codelineno-1-22" name="__codelineno-1-22" href="#__codelineno-1-22"></a> <span class="c1"># Check if the user has permission to change the tenant, via being a member of &quot;Tenant Managers&quot;</span>
9233
+ <a id="__codelineno-1-23" name="__codelineno-1-23" href="#__codelineno-1-23"></a> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s2">&quot;user&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">groups</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;Tenant Managers&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
9234
+ <a id="__codelineno-1-24" name="__codelineno-1-24" href="#__codelineno-1-24"></a> <span class="bp">self</span><span class="o">.</span><span class="n">validation_error</span><span class="p">({</span>
9235
+ <a id="__codelineno-1-25" name="__codelineno-1-25" href="#__codelineno-1-25"></a> <span class="s2">&quot;tenant&quot;</span><span class="p">:</span> <span class="s2">&quot;You do not have permission to change the tenant&quot;</span>
9236
+ <a id="__codelineno-1-26" name="__codelineno-1-26" href="#__codelineno-1-26"></a> <span class="p">})</span>
9237
+ <a id="__codelineno-1-27" name="__codelineno-1-27" href="#__codelineno-1-27"></a>
9238
+ <a id="__codelineno-1-28" name="__codelineno-1-28" href="#__codelineno-1-28"></a>
9239
+ <a id="__codelineno-1-29" name="__codelineno-1-29" href="#__codelineno-1-29"></a><span class="n">custom_validators</span> <span class="o">=</span> <span class="p">[</span><span class="n">LocationTenantValidator</span><span class="p">]</span>
9240
+ </code></pre></div>
9148
9241
 
9149
9242
 
9150
9243
 
@@ -9122,9 +9122,6 @@
9122
9122
 
9123
9123
 
9124
9124
  <h1 id="extending-filters">Extending Filters<a class="headerlink" href="#extending-filters" title="Permanent link">&para;</a></h1>
9125
- <details class="version-added">
9126
- <summary>Added in version 1.3.0</summary>
9127
- </details>
9128
9125
  <p>Apps can extend any model-based <code>FilterSet</code> and <code>FilterForm</code> classes that are provided by the Nautobot core.</p>
9129
9126
  <p>The requirements to extend a filter set or a filter form (or both) are:</p>
9130
9127
  <ul>
@@ -9122,9 +9122,6 @@
9122
9122
 
9123
9123
 
9124
9124
  <h1 id="adding-jinja2-filters">Adding Jinja2 Filters<a class="headerlink" href="#adding-jinja2-filters" title="Permanent link">&para;</a></h1>
9125
- <details class="version-added">
9126
- <summary>Added in version 1.1.0</summary>
9127
- </details>
9128
9125
  <p>Apps can define custom Jinja2 filters to be used when rendering templates defined in computed fields. Check out the <a href="https://jinja.palletsprojects.com/en/3.0.x/api/#custom-filters">official Jinja2 documentation</a> on how to create filter functions.</p>
9129
9126
  <p>In the file that defines your filters (by default <code>jinja_filters.py</code>, but configurable in the <code>NautobotAppConfig</code> if desired), you must import the <code>library</code> module from the <code>django_jinja</code> library. Filters must then be decorated with <code>@library.filter</code>. See an example below that defines a filter called <code>leet_speak</code>.</p>
9130
9127
  <div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="kn">from</span> <span class="nn">django_jinja</span> <span class="kn">import</span> <span class="n">library</span>
@@ -9122,9 +9122,6 @@
9122
9122
 
9123
9123
 
9124
9124
  <h1 id="populating-extensibility-features">Populating Extensibility Features<a class="headerlink" href="#populating-extensibility-features" title="Permanent link">&para;</a></h1>
9125
- <details class="version-added">
9126
- <summary>Added in version 1.2.0</summary>
9127
- </details>
9128
9125
  <p>In many cases, an app may wish to make use of Nautobot's various extensibility features, such as <a href="../../../../user-guide/platform-functionality/customfield.html">custom fields</a> or <a href="../../../../user-guide/platform-functionality/relationship.html">relationships</a>. It can be useful for an app to automatically create a custom field definition or relationship definition as a consequence of being installed and activated, so that everyday usage of the app can rely upon these definitions to be present.</p>
9129
9126
  <p>To make this possible, Nautobot provides a custom <a href="https://docs.djangoproject.com/en/stable/topics/signals/">signal</a>, <code>nautobot_database_ready</code>, that apps can register to listen for. This signal is triggered when <code>nautobot-server migrate</code> or <code>nautobot-server post_upgrade</code> is run after installing an app, and provides an opportunity for the app to make any desired additions to the database at this time.</p>
9130
9127
  <p>For example, maybe we want our app to make use of a Relationship allowing each Location to be linked to our Animal model. We would define our callback function that makes sure this Relationship exists, by convention in a <code>signals.py</code> file:</p>
@@ -9122,9 +9122,6 @@
9122
9122
 
9123
9123
 
9124
9124
  <h1 id="implementing-secrets-providers">Implementing Secrets Providers<a class="headerlink" href="#implementing-secrets-providers" title="Permanent link">&para;</a></h1>
9125
- <details class="version-added">
9126
- <summary>Added in version 1.2.0</summary>
9127
- </details>
9128
9125
  <p>An app can define and register additional providers (sources) for <a href="../../../../user-guide/platform-functionality/secret.html">Secrets</a>, allowing Nautobot to retrieve secret values from additional systems or data sources. By default, Nautobot looks for an iterable named <code>secrets_providers</code> within a <code>secrets.py</code> file. (This can be overridden by setting <code>secrets_providers</code> to a custom value on the app's <code>NautobotAppConfig</code>.)</p>
9129
9126
  <p>To define a new <code>SecretsProvider</code> subclass, we must specify the following:</p>
9130
9127
  <ul>
@@ -9122,9 +9122,6 @@
9122
9122
 
9123
9123
 
9124
9124
  <h1 id="prometheus-metrics">Prometheus Metrics<a class="headerlink" href="#prometheus-metrics" title="Permanent link">&para;</a></h1>
9125
- <details class="version-added">
9126
- <summary>Added in version 1.5.13</summary>
9127
- </details>
9128
9125
  <p>It is possible for Nautobot apps to provide their own <a href="../../../user-guide/administration/guides/prometheus-metrics.html">Prometheus metrics</a>. There are two general ways to achieve this:</p>
9129
9126
  <ol>
9130
9127
  <li>Use the <code>prometheus_client</code> library directly in your app code. Depending on whether that code runs in the web server or the worker context, the metric will show up in the respective <code>/metrics</code> endpoint(s) (i.e. metrics generated in the worker context show up in the worker's endpoint and those generated in the web application's context show up in the web application's endpoint).</li>
@@ -9232,14 +9232,8 @@
9232
9232
  <h1 id="testing-apps">Testing Apps<a class="headerlink" href="#testing-apps" title="Permanent link">&para;</a></h1>
9233
9233
  <p>In general apps can be tested like other Django apps. In most cases you'll want to run your automated tests via the <code>nautobot-server test &lt;app_module&gt;</code> command or, if using the <code>coverage</code> Python library, <code>coverage run --module nautobot.core.cli test &lt;app_module&gt;</code>.</p>
9234
9234
  <h2 id="factories">Factories<a class="headerlink" href="#factories" title="Permanent link">&para;</a></h2>
9235
- <details class="version-added">
9236
- <summary>Added in version 1.5.0</summary>
9237
- </details>
9238
9235
  <p>The <a href="../../../user-guide/administration/configuration/settings.html#test_use_factories"><code>TEST_USE_FACTORIES</code></a> setting defaults to <code>False</code> when testing apps, primarily for backwards-compatibility reasons. It can prove a useful way of populating a baseline of Nautobot database data for your tests and save you the trouble of creating a large amount of baseline data yourself. We recommend adding <a href="https://pypi.org/project/factory-boy/"><code>factory-boy</code></a> to your app's development dependencies and settings <code>TEST_USE_FACTORIES = True</code> in your app's development/test <code>nautobot_config.py</code> to take advantage of this.</p>
9239
9236
  <h2 id="performance-tests">Performance Tests<a class="headerlink" href="#performance-tests" title="Permanent link">&para;</a></h2>
9240
- <details class="version-added">
9241
- <summary>Added in version 1.5.0</summary>
9242
- </details>
9243
9237
  <h2 id="running-performance-tests">Running Performance Tests<a class="headerlink" href="#running-performance-tests" title="Permanent link">&para;</a></h2>
9244
9238
  <p>You need to install <code>django-slowtests</code> as a part of your app dev dependency to run performance tests. It has a very intuitive way to measure the performance of your own tests for your app (all you have to do is tag your tests with <code>performance</code>) and do <code>invoke performance-test</code> to get the time to run your tests with <code>NautobotPerformanceTestRunner</code>.</p>
9245
9239
  <p><code>NautobotPerformanceTestRunner</code> is used by adding the flag <code>--testrunner nautobot.core.tests.runner.NautobotPerformanceTestRunner</code> to the <code>coverage run</code> command used for unit tests. This flag will replace the default <code>NautobotTestRunner</code> while retaining all its functionalities with the addition of performance evaluation after test
@@ -9122,9 +9122,6 @@
9122
9122
 
9123
9123
 
9124
9124
  <h1 id="adding-a-banner">Adding a Banner<a class="headerlink" href="#adding-a-banner" title="Permanent link">&para;</a></h1>
9125
- <details class="version-added">
9126
- <summary>Added in version 1.2.0</summary>
9127
- </details>
9128
9125
  <p>An app can provide a function that renders a custom banner on any number of Nautobot views. By default Nautobot looks for a function <code>banner()</code> inside of <code>banner.py</code>. (This can be overridden by setting <code>banner_function</code> to a custom value on the app's <code>NautobotAppConfig</code>.)</p>
9129
9126
  <p>This function currently receives a single argument, <code>context</code>, which is the <a href="https://docs.djangoproject.com/en/stable/ref/templates/api/#using-requestcontext">Django request context</a> in which the current page is being rendered. The function can return <code>None</code> if no banner is needed for a given page view, or can return a <code>Banner</code> object describing the banner contents. Here's a simple example <code>banner.py</code>:</p>
9130
9127
  <div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1"># banner.py</span>
@@ -9122,9 +9122,6 @@
9122
9122
 
9123
9123
 
9124
9124
  <h1 id="adding-home-page-content">Adding Home Page Content<a class="headerlink" href="#adding-home-page-content" title="Permanent link">&para;</a></h1>
9125
- <details class="version-added">
9126
- <summary>Added in version 1.2.0</summary>
9127
- </details>
9128
9125
  <p>Apps can add content to the Nautobot home page. By default, Nautobot looks for a <code>layout</code> list inside of <code>homepage.py</code>. (This can be overridden by setting <code>homepage_layout</code> to a custom value on the app's <code>NautobotAppConfig</code>.)</p>
9129
9126
  <p>Using a key and weight system, a developer can integrate the app content amongst existing panels, groups, and items and/or create entirely new panels as desired.</p>
9130
9127
  <p>More documentation and examples can be found in the guide on <a href="../../../core/homepage.html">Home Page Panels</a>.</p>
@@ -9457,9 +9457,6 @@
9457
9457
  </code></pre></div>
9458
9458
  <p>Note that a <code>Tab</code> defines its contents directly (as <code>panels</code>) while the <code>DistinctViewTab</code> instead provides a <code>url_name</code> to the related URL that it should link against.</p>
9459
9459
  <h3 id="via-detail_tabs-deprecated">Via <code>detail_tabs()</code> (Deprecated)<a class="headerlink" href="#via-detail_tabs-deprecated" title="Permanent link">&para;</a></h3>
9460
- <details class="version-added">
9461
- <summary>Added in version 1.4.0</summary>
9462
- </details>
9463
9460
  <p>The <code>TemplateExtension.detail_tabs()</code> method should return a list of dicts, each of which has the keys <code>"title"</code> and <code>"url"</code>. In addition, in order for tabs to work properly:</p>
9464
9461
  <ul>
9465
9462
  <li>The <code>"url"</code> key should typically be a URL that includes <code>self.context["object"].pk</code> in some form (so that the URL may know which object is being referenced)</li>
@@ -9124,9 +9124,6 @@
9124
9124
 
9125
9125
 
9126
9126
  <h1 id="replacing-views">Replacing Views<a class="headerlink" href="#replacing-views" title="Permanent link">&para;</a></h1>
9127
- <details class="version-added">
9128
- <summary>Added in version 1.4.0</summary>
9129
- </details>
9130
9127
  <p>You may override any of the core or app views by providing an <code>override_views</code> <code>dict</code> in an app's <code>views.py</code> file.</p>
9131
9128
  <p>To override a view, you must specify the view's fully qualified name as the <code>dict</code> key which consists of the app name followed by the view's name separated by a colon, for instance <code>dcim:device</code>. The <code>dict</code> value should be the overriding view function.</p>
9132
9129
  <p>A simple example to override the device detail view:</p>
@@ -9182,15 +9182,9 @@
9182
9182
  <p class="admonition-title">Warning</p>
9183
9183
  <p>Currently preferred way of implementing views is to use <a href="nautobotuiviewset.html"><code>NautobotUIViewSet</code></a></p>
9184
9184
  </div>
9185
- <details class="version-added">
9186
- <summary>Added in version 1.1.0</summary>
9187
- <p>Via <a href="https://github.com/nautobot/nautobot/issues/14">PR #14</a>, some <code>generic</code> views have been exposed to help aid in App development. These views have some requirements that must be in place in order to work. These can be used by importing them from <code>from nautobot.core.views import generic</code>.</p>
9188
- </details>
9185
+ <p>Some <code>generic</code> views have been exposed to help aid in App development. These views have some requirements that must be in place in order to work. These can be used by importing them from <code>from nautobot.core.views import generic</code>.</p>
9189
9186
  <p>More documentation and examples can be found in <a href="../../../core/generic-views.html">Generic Views</a> guide.</p>
9190
9187
  <h2 id="note-url-endpoint">Note URL Endpoint<a class="headerlink" href="#note-url-endpoint" title="Permanent link">&para;</a></h2>
9191
- <details class="version-added">
9192
- <summary>Added in version 1.4.0</summary>
9193
- </details>
9194
9188
  <p>Models that inherit from <code>PrimaryModel</code> and <code>OrganizationalModel</code> can have notes associated. In order to utilize this new feature you will need to add the endpoint to <code>urls.py</code>. Here is an option to be able to support both 1.4+ and older versions of Nautobot:</p>
9195
9189
  <div class="admonition tip">
9196
9190
  <p class="admonition-title">Tip</p>
@@ -9280,9 +9280,6 @@
9280
9280
 
9281
9281
 
9282
9282
  <h1 id="nautobotuiviewset">NautobotUIViewSet<a class="headerlink" href="#nautobotuiviewset" title="Permanent link">&para;</a></h1>
9283
- <details class="version-added">
9284
- <summary>Added in version 1.4.0</summary>
9285
- </details>
9286
9283
  <p>New in Nautobot 1.4 is the debut of <code>NautobotUIViewSet</code>: A powerful app development tool that can save app developer hundreds of lines of code compared to using legacy <code>generic.views</code>. Using it to gain access to default functionalities previous provided by <code>generic.views</code> such as <code>create()</code>, <code>update()</code>, <code>partial_update()</code>, <code>bulk_update()</code>, <code>destroy()</code>, <code>bulk_destroy()</code>, <code>retrieve()</code> and <code>list()</code> actions.</p>
9287
9284
  <p>Note that this ViewSet is catered specifically to the UI, not the API.</p>
9288
9285
  <p>Concrete examples on how to use <code>NautobotUIViewSet</code> resides in <code>nautobot.circuits.views</code>.</p>
@@ -9443,10 +9440,6 @@ The framework provides many pre-built panel types.</p>
9443
9440
  <p>If you do not provide your own templates in the <code>yourapp/templates/yourapp</code> folder, <code>NautobotUIViewSet</code> will fall back to <code>generic/object_{self.action}.html</code>.</p>
9444
9441
  <p>Since in many cases the <code>create</code> and <code>update</code> templates for a model will be identical, you are not required to create both. If you provide a <code>{app_label}/{model_opts.model_name}_create.html</code> file but not a <code>{app_label}/{model_opts.model_name}_update.html</code> file, then when you update an object, it will fall back to <code>{app_label}/{model_opts.model_name}_create.html</code> and vice versa.</p>
9445
9442
  <h3 id="adding-custom-views-to-nautobotuiviewset-nautobotuiviewsetrouter">Adding Custom Views To NautobotUIViewSet &amp; NautobotUIViewSetRouter<a class="headerlink" href="#adding-custom-views-to-nautobotuiviewset-nautobotuiviewsetrouter" title="Permanent link">&para;</a></h3>
9446
- <details class="version-changed">
9447
- <summary>Changed in version 1.6.0</summary>
9448
- <p>Via <a href="https://github.com/nautobot/nautobot/pull/4045">PR #4045</a>, notes and changelog views provided by mixins have now been moved to this pattern.</p>
9449
- </details>
9450
9443
  <p>Django REST Framework provides the ability to decorate a method on a ViewSet with <code>@action(detail=True)</code> to add the method as a view to the ViewSetRouter. This method must return a fully rendered HTML view.</p>
9451
9444
  <p>Below is an example of adding a custom action view to an App's ViewSet. A few considerations to keep in mind:</p>
9452
9445
  <ul>
@@ -9154,10 +9154,6 @@
9154
9154
  <a id="__codelineno-0-27" name="__codelineno-0-27" href="#__codelineno-0-27"></a><span class="p">]</span>
9155
9155
  <a id="__codelineno-0-28" name="__codelineno-0-28" href="#__codelineno-0-28"></a><span class="n">urlpatterns</span> <span class="o">+=</span> <span class="n">router</span><span class="o">.</span><span class="n">urls</span>
9156
9156
  </code></pre></div>
9157
- <details class="version-added">
9158
- <summary>Added in version 1.5.1</summary>
9159
- <p>Changelog and Notes views and URLs are now provided in the NautobotUIViewSet and NautobotUIViewSetRouter.</p>
9160
- </details>
9161
9157
 
9162
9158
 
9163
9159
 
@@ -9124,9 +9124,6 @@
9124
9124
 
9125
9125
 
9126
9126
  <h1 id="note-url-endpoint">Note URL Endpoint<a class="headerlink" href="#note-url-endpoint" title="Permanent link">&para;</a></h1>
9127
- <details class="version-added">
9128
- <summary>Added in version 1.4.0</summary>
9129
- </details>
9130
9127
  <p>Models that inherit from <code>PrimaryModel</code> and <code>OrganizationalModel</code> can have notes associated. In order to utilize this new feature you will need to add the endpoint to <code>urls.py</code>. Here is an option to be able to support both 1.4+ and older versions of Nautobot:</p>
9131
9128
  <div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
9132
9129
  <a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a> <span class="n">path</span><span class="p">(</span><span class="s1">&#39;random/&#39;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">RandomAnimalView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;random_animal&#39;</span><span class="p">),</span>