Example #1
0
class NestedGroupModel(ChangeLoggingMixin, CustomFieldsMixin,
                       CustomValidationMixin, BigIDModel, MPTTModel):
    """
    Base model for objects which are used to form a hierarchy (regions, locations, etc.). These models nest
    recursively using MPTT. Within each parent, each child instance must have a unique name.
    """
    parent = TreeForeignKey(to='self',
                            on_delete=models.CASCADE,
                            related_name='children',
                            blank=True,
                            null=True,
                            db_index=True)
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=200, blank=True)

    objects = TreeManager()

    class Meta:
        abstract = True

    class MPTTMeta:
        order_insertion_by = ('name', )

    def __str__(self):
        return self.name

    def clean(self):
        super().clean()

        # An MPTT model cannot be its own parent
        if self.pk and self.parent_id == self.pk:
            raise ValidationError({"parent": "Cannot assign self as parent."})
Example #2
0
class Region(MPTTModel, ChangeLoggedModel):
    """
    Sites can be grouped within geographic Regions.
    """
    parent = TreeForeignKey(to='self',
                            on_delete=models.CASCADE,
                            related_name='children',
                            blank=True,
                            null=True,
                            db_index=True)
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    description = models.CharField(max_length=200, blank=True)

    objects = TreeManager()

    csv_headers = ['name', 'slug', 'parent', 'description']

    class MPTTMeta:
        order_insertion_by = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return "{}?region={}".format(reverse('dcim:site_list'), self.slug)

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.parent.name if self.parent else None,
            self.description,
        )

    def get_site_count(self):
        return Site.objects.filter(
            Q(region=self) | Q(region__in=self.get_descendants())).count()

    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']))

    def clean(self):
        super().clean()

        # An MPTT model cannot be its own parent
        if self.pk and self.parent_id == self.pk:
            raise ValidationError({"parent": "Cannot assign self as parent."})
Example #3
0
class InventoryItem(MPTTModel, ComponentModel):
    """
    An InventoryItem represents a serialized piece of hardware within a Device, such as a line card or power supply.
    InventoryItems are used only for inventory purposes.
    """
    parent = TreeForeignKey(
        to='self',
        on_delete=models.CASCADE,
        related_name='child_items',
        blank=True,
        null=True,
        db_index=True
    )
    manufacturer = models.ForeignKey(
        to='dcim.Manufacturer',
        on_delete=models.PROTECT,
        related_name='inventory_items',
        blank=True,
        null=True
    )
    part_id = models.CharField(
        max_length=50,
        verbose_name='Part ID',
        blank=True,
        help_text='Manufacturer-assigned part identifier'
    )
    serial = models.CharField(
        max_length=50,
        verbose_name='Serial number',
        blank=True
    )
    asset_tag = models.CharField(
        max_length=50,
        unique=True,
        blank=True,
        null=True,
        verbose_name='Asset tag',
        help_text='A unique tag used to identify this item'
    )
    discovered = models.BooleanField(
        default=False,
        help_text='This item was automatically discovered'
    )

    objects = TreeManager()

    clone_fields = ['device', 'parent', 'manufacturer', 'part_id']

    class Meta:
        ordering = ('device__id', 'parent__id', '_name')
        unique_together = ('device', 'parent', 'name')

    def get_absolute_url(self):
        return reverse('dcim:inventoryitem', kwargs={'pk': self.pk})
Example #4
0
class TenantGroup(MPTTModel, ChangeLoggedModel):
    """
    An arbitrary collection of Tenants.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, 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']))

    def clean(self):
        super().clean()

        # An MPTT model cannot be its own parent
        if self.pk and self.parent_id == self.pk:
            raise ValidationError({"parent": "Cannot assign self as parent."})
Example #5
0
class RackGroup(MPTTModel, ChangeLoggedModel):
    """
    Racks can be grouped as subsets within a Site. The scope of a group will depend on how Sites are defined. For
    example, if a Site spans a corporate campus, a RackGroup might be defined to represent each building within that
    campus. If a Site instead represents a single building, a RackGroup might represent a single room or floor.
    """
    name = models.CharField(
        max_length=100
    )
    slug = models.SlugField(
        max_length=100
    )
    site = models.ForeignKey(
        to='dcim.Site',
        on_delete=models.CASCADE,
        related_name='rack_groups'
    )
    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 = ['site', 'parent', 'name', 'slug', 'description']

    class Meta:
        ordering = ['site', 'name']
        unique_together = [
            ['site', 'name'],
            ['site', 'slug'],
        ]

    class MPTTMeta:
        order_insertion_by = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return "{}?group_id={}".format(reverse('dcim:rack_list'), self.pk)

    def to_csv(self):
        return (
            self.site,
            self.parent.name if self.parent else '',
            self.name,
            self.slug,
            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'])
        )

    def clean(self):
        super().clean()

        # Parent RackGroup (if any) must belong to the same Site
        if self.parent and self.parent.site != self.site:
            raise ValidationError(f"Parent rack group ({self.parent}) must belong to the same site ({self.site})")
Example #6
0
class Region(MPTTModel, ChangeLoggedModel):
    """
    Sites can be grouped within geographic Regions.
    """
    parent = TreeForeignKey(
        to='self',
        on_delete=models.CASCADE,
        related_name='children',
        blank=True,
        null=True,
        db_index=True,
        verbose_name='родитель'
    )
    name = models.CharField(
        max_length=50,
        unique=True,
        verbose_name='название'
    )
    slug = models.SlugField(
        unique=True
    )
    description = models.CharField(
        max_length=200,
        blank=True,
        verbose_name='описание'
    )

    objects = TreeManager()

    csv_headers = ['name', 'slug', 'parent', 'description']

    class MPTTMeta:
        order_insertion_by = ['name']

    class Meta:
        verbose_name = 'регион'
        verbose_name_plural = 'регионы'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return "{}?region={}".format(reverse('dcim:site_list'), self.slug)

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.parent.name if self.parent else None,
            self.description,
        )

    def get_site_count(self):
        return Site.objects.filter(
            Q(region=self) |
            Q(region__in=self.get_descendants())
        ).count()

    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'])
        )