from django.contrib.contenttypes.fields import GenericRelation from django.db import models from django.urls import reverse from mptt.models import MPTTModel, TreeForeignKey from taggit.managers import TaggableManager from extras.models import CustomFieldModel, ObjectChange, TaggedItem from extras.utils import extras_features from utilities.models import ChangeLoggedModel from utilities.mptt import TreeManager from utilities.querysets import RestrictedQuerySet from utilities.utils import serialize_object __all__ = ( 'Tenant', 'TenantGroup', ) class TenantGroup(MPTTModel, ChangeLoggedModel): """ An arbitrary collection of Tenants. """ name = models.CharField( max_length=50, unique=True ) slug = models.SlugField( unique=True ) parent = TreeForeignKey( to='self', on_delete=models.CASCADE, related_name='children', blank=True, null=True, db_index=True ) description = models.CharField( max_length=200, blank=True ) objects = TreeManager() csv_headers = ['name', 'slug', 'parent', 'description'] class Meta: ordering = ['name'] class MPTTMeta: order_insertion_by = ['name'] def __str__(self): return self.name def get_absolute_url(self): return "{}?group={}".format(reverse('tenancy:tenant_list'), self.slug) def to_csv(self): return ( self.name, self.slug, self.parent.name if self.parent else '', self.description, ) def to_objectchange(self, action): # Remove MPTT-internal fields return ObjectChange( changed_object=self, object_repr=str(self), action=action, object_data=serialize_object(self, exclude=['level', 'lft', 'rght', 'tree_id']) ) @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks') class Tenant(ChangeLoggedModel, CustomFieldModel): """ A Tenant represents an organization served by the NetBox owner. This is typically a customer or an internal department. """ name = models.CharField( max_length=30, unique=True ) slug = models.SlugField( unique=True ) group = models.ForeignKey( to='tenancy.TenantGroup', on_delete=models.SET_NULL, related_name='tenants', blank=True, null=True ) description = models.CharField( max_length=200, blank=True ) comments = models.TextField( blank=True ) custom_field_values = GenericRelation( to='extras.CustomFieldValue', content_type_field='obj_type', object_id_field='obj_id' ) tags = TaggableManager(through=TaggedItem) objects = RestrictedQuerySet.as_manager() csv_headers = ['name', 'slug', 'group', 'description', 'comments'] clone_fields = [ 'group', 'description', ] class Meta: ordering = ['group', 'name'] def __str__(self): return self.name def get_absolute_url(self): return reverse('tenancy:tenant', args=[self.slug]) def to_csv(self): return ( self.name, self.slug, self.group.name if self.group else None, self.description, self.comments, )