content: from django.contrib.postgres.fields import ArrayField
  from django.db import models
  from django.urls import reverse
  from django.utils.translation import gettext_lazy as _
  
  from netbox.models.features import CloningMixin
  from utilities.querysets import RestrictedQuerySet
  
  __all__ = (
      'ObjectPermission',
  )
  
  
  class ObjectPermission(CloningMixin, models.Model):
      """
      A mapping of view, add, change, and/or delete permission for users and/or groups to an arbitrary set of objects
      identified by ORM query parameters.
      """
      name = models.CharField(
          verbose_name=_('name'),
          max_length=100
      )
      description = models.CharField(
          verbose_name=_('description'),
          max_length=200,
          blank=True
      )
      enabled = models.BooleanField(
          verbose_name=_('enabled'),
          default=True
      )
      object_types = models.ManyToManyField(
          to='contenttypes.ContentType',
          related_name='object_permissions'
      )
      actions = ArrayField(
          base_field=models.CharField(max_length=30),
          help_text=_("The list of actions granted by this permission")
      )
      constraints = models.JSONField(
          blank=True,
          null=True,
          verbose_name=_('constraints'),
          help_text=_("Queryset filter matching the applicable objects of the selected type(s)")
      )
  
      clone_fields = (
          'description', 'enabled', 'object_types', 'actions', 'constraints',
      )
  
      objects = RestrictedQuerySet.as_manager()
  
      class Meta:
          ordering = ['name']
          verbose_name = _('permission')
          verbose_name_plural = _('permissions')
  
      def __str__(self):
          return self.name
  
      @property
      def can_view(self):
          return 'view' in self.actions
  
      @property
      def can_add(self):
          return 'add' in self.actions
  
      @property
      def can_change(self):
          return 'change' in self.actions
  
      @property
      def can_delete(self):
          return 'delete' in self.actions
  
      def list_constraints(self):
          """
          Return all constraint sets as a list (even if only a single set is defined).
          """
          if type(self.constraints) is not list:
              return [self.constraints]
          return self.constraints
  
      def get_absolute_url(self):
          return reverse('users:objectpermission', args=[self.pk])
  