models.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.db import models
  4. from django.urls import reverse
  5. from mptt.models import MPTTModel, TreeForeignKey
  6. from extras.utils import extras_features
  7. from netbox.models import ChangeLoggedModel, NestedGroupModel, OrganizationalModel, PrimaryModel
  8. from utilities.querysets import RestrictedQuerySet
  9. from .choices import *
  10. __all__ = (
  11. 'ContactAssignment',
  12. 'Contact',
  13. 'ContactGroup',
  14. 'ContactRole',
  15. 'Tenant',
  16. 'TenantGroup',
  17. )
  18. #
  19. # Tenants
  20. #
  21. @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
  22. class TenantGroup(NestedGroupModel):
  23. """
  24. An arbitrary collection of Tenants.
  25. """
  26. name = models.CharField(
  27. max_length=100,
  28. unique=True
  29. )
  30. slug = models.SlugField(
  31. max_length=100,
  32. unique=True
  33. )
  34. parent = TreeForeignKey(
  35. to='self',
  36. on_delete=models.CASCADE,
  37. related_name='children',
  38. blank=True,
  39. null=True,
  40. db_index=True
  41. )
  42. description = models.CharField(
  43. max_length=200,
  44. blank=True
  45. )
  46. class Meta:
  47. ordering = ['name']
  48. def get_absolute_url(self):
  49. return reverse('tenancy:tenantgroup', args=[self.pk])
  50. @extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks')
  51. class Tenant(PrimaryModel):
  52. """
  53. A Tenant represents an organization served by the NetBox owner. This is typically a customer or an internal
  54. department.
  55. """
  56. name = models.CharField(
  57. max_length=100,
  58. unique=True
  59. )
  60. slug = models.SlugField(
  61. max_length=100,
  62. unique=True
  63. )
  64. group = models.ForeignKey(
  65. to='tenancy.TenantGroup',
  66. on_delete=models.SET_NULL,
  67. related_name='tenants',
  68. blank=True,
  69. null=True
  70. )
  71. description = models.CharField(
  72. max_length=200,
  73. blank=True
  74. )
  75. comments = models.TextField(
  76. blank=True
  77. )
  78. # Generic relations
  79. contacts = GenericRelation(
  80. to='tenancy.ContactAssignment'
  81. )
  82. objects = RestrictedQuerySet.as_manager()
  83. clone_fields = [
  84. 'group', 'description',
  85. ]
  86. class Meta:
  87. ordering = ['name']
  88. def __str__(self):
  89. return self.name
  90. def get_absolute_url(self):
  91. return reverse('tenancy:tenant', args=[self.pk])
  92. #
  93. # Contacts
  94. #
  95. @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
  96. class ContactGroup(NestedGroupModel):
  97. """
  98. An arbitrary collection of Contacts.
  99. """
  100. name = models.CharField(
  101. max_length=100,
  102. unique=True
  103. )
  104. slug = models.SlugField(
  105. max_length=100,
  106. unique=True
  107. )
  108. parent = TreeForeignKey(
  109. to='self',
  110. on_delete=models.CASCADE,
  111. related_name='children',
  112. blank=True,
  113. null=True,
  114. db_index=True
  115. )
  116. description = models.CharField(
  117. max_length=200,
  118. blank=True
  119. )
  120. class Meta:
  121. ordering = ['name']
  122. def get_absolute_url(self):
  123. return reverse('tenancy:contactgroup', args=[self.pk])
  124. @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
  125. class ContactRole(OrganizationalModel):
  126. """
  127. Functional role for a Contact assigned to an object.
  128. """
  129. name = models.CharField(
  130. max_length=100,
  131. unique=True
  132. )
  133. slug = models.SlugField(
  134. max_length=100,
  135. unique=True
  136. )
  137. description = models.CharField(
  138. max_length=200,
  139. blank=True,
  140. )
  141. objects = RestrictedQuerySet.as_manager()
  142. class Meta:
  143. ordering = ['name']
  144. def __str__(self):
  145. return self.name
  146. def get_absolute_url(self):
  147. return reverse('tenancy:contactrole', args=[self.pk])
  148. @extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks')
  149. class Contact(PrimaryModel):
  150. """
  151. Contact information for a particular object(s) in NetBox.
  152. """
  153. group = models.ForeignKey(
  154. to='tenancy.ContactGroup',
  155. on_delete=models.SET_NULL,
  156. related_name='contacts',
  157. blank=True,
  158. null=True
  159. )
  160. name = models.CharField(
  161. max_length=100
  162. )
  163. title = models.CharField(
  164. max_length=100,
  165. blank=True
  166. )
  167. phone = models.CharField(
  168. max_length=50,
  169. blank=True
  170. )
  171. email = models.EmailField(
  172. blank=True
  173. )
  174. address = models.CharField(
  175. max_length=200,
  176. blank=True
  177. )
  178. comments = models.TextField(
  179. blank=True
  180. )
  181. objects = RestrictedQuerySet.as_manager()
  182. clone_fields = [
  183. 'group',
  184. ]
  185. class Meta:
  186. ordering = ['name']
  187. def __str__(self):
  188. return self.name
  189. def get_absolute_url(self):
  190. return reverse('tenancy:contact', args=[self.pk])
  191. @extras_features('webhooks')
  192. class ContactAssignment(ChangeLoggedModel):
  193. content_type = models.ForeignKey(
  194. to=ContentType,
  195. on_delete=models.CASCADE
  196. )
  197. object_id = models.PositiveIntegerField()
  198. object = GenericForeignKey(
  199. ct_field='content_type',
  200. fk_field='object_id'
  201. )
  202. contact = models.ForeignKey(
  203. to='tenancy.Contact',
  204. on_delete=models.PROTECT,
  205. related_name='assignments'
  206. )
  207. role = models.ForeignKey(
  208. to='tenancy.ContactRole',
  209. on_delete=models.PROTECT,
  210. related_name='assignments'
  211. )
  212. priority = models.CharField(
  213. max_length=50,
  214. choices=ContactPriorityChoices,
  215. blank=True
  216. )
  217. objects = RestrictedQuerySet.as_manager()
  218. class Meta:
  219. ordering = ('priority', 'contact')