from django import forms
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _

from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup
from tenancy.models import Tenant, TenantGroup
from utilities.forms import (
    add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect,
    CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField,
    JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES,
)
from virtualization.models import Cluster, ClusterGroup
from .choices import *
from .models import ConfigContext, CustomField, ImageAttachment, JournalEntry, ObjectChange, Tag
from .utils import FeatureQuery


#
# Custom fields
#

class CustomFieldForm(forms.Form):
    """
    Extend Form to include custom field support.
    """
    model = None

    def __init__(self, *args, **kwargs):
        if self.model is None:
            raise NotImplementedError("CustomFieldForm must specify a model class.")
        self.custom_fields = []

        super().__init__(*args, **kwargs)

        # Append relevant custom fields to the form instance
        obj_type = ContentType.objects.get_for_model(self.model)
        for cf in CustomField.objects.filter(content_types=obj_type):
            field_name = 'cf_{}'.format(cf.name)
            self.fields[field_name] = cf.to_form_field()

            # Annotate the field in the list of CustomField form fields
            self.custom_fields.append(field_name)


class CustomFieldModelForm(forms.ModelForm):
    """
    Extend ModelForm to include custom field support.
    """
    def __init__(self, *args, **kwargs):

        self.obj_type = ContentType.objects.get_for_model(self._meta.model)
        self.custom_fields = []

        super().__init__(*args, **kwargs)

        self._append_customfield_fields()

    def _append_customfield_fields(self):
        """
        Append form fields for all CustomFields assigned to this model.
        """
        # Append form fields; assign initial values if modifying and existing object
        for cf in CustomField.objects.filter(content_types=self.obj_type):
            field_name = 'cf_{}'.format(cf.name)
            if self.instance.pk:
                self.fields[field_name] = cf.to_form_field(set_initial=False)
                self.fields[field_name].initial = self.instance.custom_field_data.get(cf.name)
            else:
                self.fields[field_name] = cf.to_form_field()

            # Annotate the field in the list of CustomField form fields
            self.custom_fields.append(field_name)

    def clean(self):

        # Save custom field data on instance
        for cf_name in self.custom_fields:
            self.instance.custom_field_data[cf_name[3:]] = self.cleaned_data.get(cf_name)

        return super().clean()


class CustomFieldModelCSVForm(CSVModelForm, CustomFieldModelForm):

    def _append_customfield_fields(self):

        # Append form fields
        for cf in CustomField.objects.filter(content_types=self.obj_type):
            field_name = 'cf_{}'.format(cf.name)
            self.fields[field_name] = cf.to_form_field(for_csv_import=True)

            # Annotate the field in the list of CustomField form fields
            self.custom_fields.append(field_name)


class CustomFieldBulkEditForm(BulkEditForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.custom_fields = []
        self.obj_type = ContentType.objects.get_for_model(self.model)

        # Add all applicable CustomFields to the form
        custom_fields = CustomField.objects.filter(content_types=self.obj_type)
        for cf in custom_fields:
            # Annotate non-required custom fields as nullable
            if not cf.required:
                self.nullable_fields.append(cf.name)
            self.fields[cf.name] = cf.to_form_field(set_initial=False, enforce_required=False)
            # Annotate this as a custom field
            self.custom_fields.append(cf.name)


class CustomFieldFilterForm(forms.Form):

    def __init__(self, *args, **kwargs):

        self.obj_type = ContentType.objects.get_for_model(self.model)

        super().__init__(*args, **kwargs)

        # Add all applicable CustomFields to the form
        custom_fields = CustomField.objects.filter(content_types=self.obj_type).exclude(
            filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED
        )
        for cf in custom_fields:
            field_name = 'cf_{}'.format(cf.name)
            self.fields[field_name] = cf.to_form_field(set_initial=True, enforce_required=False)


#
# Tags
#

class TagForm(BootstrapMixin, forms.ModelForm):
    slug = SlugField()

    class Meta:
        model = Tag
        fields = [
            'name', 'slug', 'color', 'description'
        ]
        fieldsets = (
            ('Tag', ('name', 'slug', 'color', 'description')),
        )


class TagCSVForm(CSVModelForm):
    slug = SlugField()

    class Meta:
        model = Tag
        fields = Tag.csv_headers
        help_texts = {
            'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'),
        }


class AddRemoveTagsForm(forms.Form):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Add add/remove tags fields
        self.fields['add_tags'] = DynamicModelMultipleChoiceField(
            queryset=Tag.objects.all(),
            required=False
        )
        self.fields['remove_tags'] = DynamicModelMultipleChoiceField(
            queryset=Tag.objects.all(),
            required=False
        )


class TagFilterForm(BootstrapMixin, forms.Form):
    model = Tag
    q = forms.CharField(
        required=False,
        label=_('Search')
    )
    content_type_id = ContentTypeMultipleChoiceField(
        queryset=ContentType.objects.filter(FeatureQuery('tags').get_query()),
        required=False,
        label=_('Tagged object type')
    )


class TagBulkEditForm(BootstrapMixin, BulkEditForm):
    pk = forms.ModelMultipleChoiceField(
        queryset=Tag.objects.all(),
        widget=forms.MultipleHiddenInput
    )
    color = forms.CharField(
        max_length=6,
        required=False,
        widget=ColorSelect()
    )
    description = forms.CharField(
        max_length=200,
        required=False
    )

    class Meta:
        nullable_fields = ['description']


#
# Config contexts
#

class ConfigContextForm(BootstrapMixin, forms.ModelForm):
    regions = DynamicModelMultipleChoiceField(
        queryset=Region.objects.all(),
        required=False
    )
    site_groups = DynamicModelMultipleChoiceField(
        queryset=SiteGroup.objects.all(),
        required=False
    )
    sites = DynamicModelMultipleChoiceField(
        queryset=Site.objects.all(),
        required=False
    )
    device_types = DynamicModelMultipleChoiceField(
        queryset=DeviceType.objects.all(),
        required=False
    )
    roles = DynamicModelMultipleChoiceField(
        queryset=DeviceRole.objects.all(),
        required=False
    )
    platforms = DynamicModelMultipleChoiceField(
        queryset=Platform.objects.all(),
        required=False
    )
    cluster_groups = DynamicModelMultipleChoiceField(
        queryset=ClusterGroup.objects.all(),
        required=False
    )
    clusters = DynamicModelMultipleChoiceField(
        queryset=Cluster.objects.all(),
        required=False
    )
    tenant_groups = DynamicModelMultipleChoiceField(
        queryset=TenantGroup.objects.all(),
        required=False
    )
    tenants = DynamicModelMultipleChoiceField(
        queryset=Tenant.objects.all(),
        required=False
    )
    tags = DynamicModelMultipleChoiceField(
        queryset=Tag.objects.all(),
        required=False
    )
    data = JSONField(
        label=''
    )

    class Meta:
        model = ConfigContext
        fields = (
            'name', 'weight', 'description', 'is_active', 'regions', 'site_groups', 'sites', 'roles', 'device_types',
            'platforms', 'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', 'data',
        )


class ConfigContextBulkEditForm(BootstrapMixin, BulkEditForm):
    pk = forms.ModelMultipleChoiceField(
        queryset=ConfigContext.objects.all(),
        widget=forms.MultipleHiddenInput
    )
    weight = forms.IntegerField(
        required=False,
        min_value=0
    )
    is_active = forms.NullBooleanField(
        required=False,
        widget=BulkEditNullBooleanSelect()
    )
    description = forms.CharField(
        required=False,
        max_length=100
    )

    class Meta:
        nullable_fields = [
            'description',
        ]


class ConfigContextFilterForm(BootstrapMixin, forms.Form):
    field_order = [
        'q', 'region_id', 'site_group_id', 'site_id', 'role_id', 'platform_id', 'cluster_group_id', 'cluster_id',
        'tenant_group_id', 'tenant_id',
    ]
    q = forms.CharField(
        required=False,
        label=_('Search')
    )
    region_id = DynamicModelMultipleChoiceField(
        queryset=Region.objects.all(),
        required=False,
        label=_('Regions')
    )
    site_group_id = DynamicModelMultipleChoiceField(
        queryset=SiteGroup.objects.all(),
        required=False,
        label=_('Site groups')
    )
    site_id = DynamicModelMultipleChoiceField(
        queryset=Site.objects.all(),
        required=False,
        label=_('Sites')
    )
    device_type_id = DynamicModelMultipleChoiceField(
        queryset=DeviceType.objects.all(),
        required=False,
        label=_('Device types')
    )
    role_id = DynamicModelMultipleChoiceField(
        queryset=DeviceRole.objects.all(),
        required=False,
        label=_('Roles')
    )
    platform_id = DynamicModelMultipleChoiceField(
        queryset=Platform.objects.all(),
        required=False,
        label=_('Platforms')
    )
    cluster_group_id = DynamicModelMultipleChoiceField(
        queryset=ClusterGroup.objects.all(),
        required=False,
        label=_('Cluster groups')
    )
    cluster_id = DynamicModelMultipleChoiceField(
        queryset=Cluster.objects.all(),
        required=False,
        label=_('Clusters')
    )
    tenant_group_id = DynamicModelMultipleChoiceField(
        queryset=TenantGroup.objects.all(),
        required=False,
        label=_('Tenant groups')
    )
    tenant_id = DynamicModelMultipleChoiceField(
        queryset=Tenant.objects.all(),
        required=False,
        label=_('Tenant')
    )
    tag = DynamicModelMultipleChoiceField(
        queryset=Tag.objects.all(),
        to_field_name='slug',
        required=False,
        label=_('Tags')
    )


#
# Filter form for local config context data
#

class LocalConfigContextFilterForm(forms.Form):
    local_context_data = forms.NullBooleanField(
        required=False,
        label=_('Has local config context data'),
        widget=StaticSelect2(
            choices=BOOLEAN_WITH_BLANK_CHOICES
        )
    )


#
# Image attachments
#

class ImageAttachmentForm(BootstrapMixin, forms.ModelForm):

    class Meta:
        model = ImageAttachment
        fields = [
            'name', 'image',
        ]


#
# Journal entries
#

class JournalEntryForm(BootstrapMixin, forms.ModelForm):
    comments = CommentField()

    class Meta:
        model = JournalEntry
        fields = ['assigned_object_type', 'assigned_object_id', 'kind', 'comments']
        widgets = {
            'assigned_object_type': forms.HiddenInput,
            'assigned_object_id': forms.HiddenInput,
        }


class JournalEntryBulkEditForm(BootstrapMixin, BulkEditForm):
    pk = forms.ModelMultipleChoiceField(
        queryset=JournalEntry.objects.all(),
        widget=forms.MultipleHiddenInput
    )
    kind = forms.ChoiceField(
        choices=JournalEntryKindChoices,
        required=False
    )
    comments = forms.CharField(
        required=False,
        widget=forms.Textarea()
    )

    class Meta:
        nullable_fields = []


class JournalEntryFilterForm(BootstrapMixin, forms.Form):
    model = JournalEntry
    q = forms.CharField(
        required=False,
        label=_('Search')
    )
    created_after = forms.DateTimeField(
        required=False,
        label=_('After'),
        widget=DateTimePicker()
    )
    created_before = forms.DateTimeField(
        required=False,
        label=_('Before'),
        widget=DateTimePicker()
    )
    created_by_id = DynamicModelMultipleChoiceField(
        queryset=User.objects.all(),
        required=False,
        label=_('User'),
        widget=APISelectMultiple(
            api_url='/api/users/users/',
        )
    )
    assigned_object_type_id = DynamicModelMultipleChoiceField(
        queryset=ContentType.objects.all(),
        required=False,
        label=_('Object Type'),
        widget=APISelectMultiple(
            api_url='/api/extras/content-types/',
        )
    )
    kind = forms.ChoiceField(
        choices=add_blank_choice(JournalEntryKindChoices),
        required=False,
        widget=StaticSelect2()
    )


#
# Change logging
#

class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
    model = ObjectChange
    q = forms.CharField(
        required=False,
        label=_('Search')
    )
    time_after = forms.DateTimeField(
        required=False,
        label=_('After'),
        widget=DateTimePicker()
    )
    time_before = forms.DateTimeField(
        required=False,
        label=_('Before'),
        widget=DateTimePicker()
    )
    action = forms.ChoiceField(
        choices=add_blank_choice(ObjectChangeActionChoices),
        required=False,
        widget=StaticSelect2()
    )
    user_id = DynamicModelMultipleChoiceField(
        queryset=User.objects.all(),
        required=False,
        label=_('User'),
        widget=APISelectMultiple(
            api_url='/api/users/users/',
        )
    )
    changed_object_type_id = DynamicModelMultipleChoiceField(
        queryset=ContentType.objects.all(),
        required=False,
        label=_('Object Type'),
        widget=APISelectMultiple(
            api_url='/api/extras/content-types/',
        )
    )


#
# Scripts
#

class ScriptForm(BootstrapMixin, forms.Form):
    _commit = forms.BooleanField(
        required=False,
        initial=True,
        label="Commit changes",
        help_text="Commit changes to the database (uncheck for a dry-run)"
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Move _commit to the end of the form
        commit = self.fields.pop('_commit')
        self.fields['_commit'] = commit

    @property
    def requires_input(self):
        """
        A boolean indicating whether the form requires user input (ignore the _commit field).
        """
        return bool(len(self.fields) > 1)

[((4906, 4917), 'utilities.forms.SlugField', 'SlugField', ([], {}), '()\n', (4915, 4917), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((5175, 5186), 'utilities.forms.SlugField', 'SlugField', ([], {}), '()\n', (5184, 5186), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((6485, 6532), 'django.forms.CharField', 'forms.CharField', ([], {'max_length': '(200)', 'required': '(False)'}), '(max_length=200, required=False)\n', (6500, 6532), False, 'from django import forms\n'), ((8011, 8030), 'utilities.forms.JSONField', 'JSONField', ([], {'label': '""""""'}), "(label='')\n", (8020, 8030), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((8550, 8597), 'django.forms.IntegerField', 'forms.IntegerField', ([], {'required': '(False)', 'min_value': '(0)'}), '(required=False, min_value=0)\n', (8568, 8597), False, 'from django import forms\n'), ((8751, 8798), 'django.forms.CharField', 'forms.CharField', ([], {'required': '(False)', 'max_length': '(100)'}), '(required=False, max_length=100)\n', (8766, 8798), False, 'from django import forms\n'), ((11508, 11522), 'utilities.forms.CommentField', 'CommentField', ([], {}), '()\n', (11520, 11522), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((11999, 12065), 'django.forms.ChoiceField', 'forms.ChoiceField', ([], {'choices': 'JournalEntryKindChoices', 'required': '(False)'}), '(choices=JournalEntryKindChoices, required=False)\n', (12016, 12065), False, 'from django import forms\n'), ((14456, 14600), 'django.forms.BooleanField', 'forms.BooleanField', ([], {'required': '(False)', 'initial': '(True)', 'label': '"""Commit changes"""', 'help_text': '"""Commit changes to the database (uncheck for a dry-run)"""'}), "(required=False, initial=True, label='Commit changes',\n    help_text='Commit changes to the database (uncheck for a dry-run)')\n", (14474, 14600), False, 'from django import forms\n'), ((1341, 1386), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', (['self.model'], {}), '(self.model)\n', (1374, 1386), False, 'from django.contrib.contenttypes.models import ContentType\n'), ((1869, 1920), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', (['self._meta.model'], {}), '(self._meta.model)\n', (1902, 1920), False, 'from django.contrib.contenttypes.models import ContentType\n'), ((3681, 3726), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', (['self.model'], {}), '(self.model)\n', (3714, 3726), False, 'from django.contrib.contenttypes.models import ContentType\n'), ((4340, 4385), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', (['self.model'], {}), '(self.model)\n', (4373, 4385), False, 'from django.contrib.contenttypes.models import ContentType\n'), ((5301, 5365), 'django.utils.safestring.mark_safe', 'mark_safe', (['"""RGB color in hexadecimal (e.g. <code>00ff00</code>)"""'], {}), "('RGB color in hexadecimal (e.g. <code>00ff00</code>)')\n", (5310, 5365), False, 'from django.utils.safestring import mark_safe\n'), ((5959, 5970), 'django.utils.translation.gettext', '_', (['"""Search"""'], {}), "('Search')\n", (5960, 5970), True, 'from django.utils.translation import gettext as _\n'), ((6148, 6171), 'django.utils.translation.gettext', '_', (['"""Tagged object type"""'], {}), "('Tagged object type')\n", (6149, 6171), True, 'from django.utils.translation import gettext as _\n'), ((6447, 6460), 'utilities.forms.ColorSelect', 'ColorSelect', ([], {}), '()\n', (6458, 6460), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((6761, 6781), 'dcim.models.Region.objects.all', 'Region.objects.all', ([], {}), '()\n', (6779, 6781), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((6880, 6903), 'dcim.models.SiteGroup.objects.all', 'SiteGroup.objects.all', ([], {}), '()\n', (6901, 6903), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((6996, 7014), 'dcim.models.Site.objects.all', 'Site.objects.all', ([], {}), '()\n', (7012, 7014), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((7114, 7138), 'dcim.models.DeviceType.objects.all', 'DeviceType.objects.all', ([], {}), '()\n', (7136, 7138), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((7231, 7255), 'dcim.models.DeviceRole.objects.all', 'DeviceRole.objects.all', ([], {}), '()\n', (7253, 7255), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((7352, 7374), 'dcim.models.Platform.objects.all', 'Platform.objects.all', ([], {}), '()\n', (7372, 7374), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((7476, 7502), 'virtualization.models.ClusterGroup.objects.all', 'ClusterGroup.objects.all', ([], {}), '()\n', (7500, 7502), False, 'from virtualization.models import Cluster, ClusterGroup\n'), ((7598, 7619), 'virtualization.models.Cluster.objects.all', 'Cluster.objects.all', ([], {}), '()\n', (7617, 7619), False, 'from virtualization.models import Cluster, ClusterGroup\n'), ((7720, 7745), 'tenancy.models.TenantGroup.objects.all', 'TenantGroup.objects.all', ([], {}), '()\n', (7743, 7745), False, 'from tenancy.models import Tenant, TenantGroup\n'), ((7840, 7860), 'tenancy.models.Tenant.objects.all', 'Tenant.objects.all', ([], {}), '()\n', (7858, 7860), False, 'from tenancy.models import Tenant, TenantGroup\n'), ((8699, 8726), 'utilities.forms.BulkEditNullBooleanSelect', 'BulkEditNullBooleanSelect', ([], {}), '()\n', (8724, 8726), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((9207, 9218), 'django.utils.translation.gettext', '_', (['"""Search"""'], {}), "('Search')\n", (9208, 9218), True, 'from django.utils.translation import gettext as _\n'), ((9291, 9311), 'dcim.models.Region.objects.all', 'Region.objects.all', ([], {}), '()\n', (9309, 9311), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((9351, 9363), 'django.utils.translation.gettext', '_', (['"""Regions"""'], {}), "('Regions')\n", (9352, 9363), True, 'from django.utils.translation import gettext as _\n'), ((9440, 9463), 'dcim.models.SiteGroup.objects.all', 'SiteGroup.objects.all', ([], {}), '()\n', (9461, 9463), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((9503, 9519), 'django.utils.translation.gettext', '_', (['"""Site groups"""'], {}), "('Site groups')\n", (9504, 9519), True, 'from django.utils.translation import gettext as _\n'), ((9590, 9608), 'dcim.models.Site.objects.all', 'Site.objects.all', ([], {}), '()\n', (9606, 9608), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((9648, 9658), 'django.utils.translation.gettext', '_', (['"""Sites"""'], {}), "('Sites')\n", (9649, 9658), True, 'from django.utils.translation import gettext as _\n'), ((9736, 9760), 'dcim.models.DeviceType.objects.all', 'DeviceType.objects.all', ([], {}), '()\n', (9758, 9760), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((9800, 9817), 'django.utils.translation.gettext', '_', (['"""Device types"""'], {}), "('Device types')\n", (9801, 9817), True, 'from django.utils.translation import gettext as _\n'), ((9888, 9912), 'dcim.models.DeviceRole.objects.all', 'DeviceRole.objects.all', ([], {}), '()\n', (9910, 9912), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((9952, 9962), 'django.utils.translation.gettext', '_', (['"""Roles"""'], {}), "('Roles')\n", (9953, 9962), True, 'from django.utils.translation import gettext as _\n'), ((10037, 10059), 'dcim.models.Platform.objects.all', 'Platform.objects.all', ([], {}), '()\n', (10057, 10059), False, 'from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup\n'), ((10099, 10113), 'django.utils.translation.gettext', '_', (['"""Platforms"""'], {}), "('Platforms')\n", (10100, 10113), True, 'from django.utils.translation import gettext as _\n'), ((10193, 10219), 'virtualization.models.ClusterGroup.objects.all', 'ClusterGroup.objects.all', ([], {}), '()\n', (10217, 10219), False, 'from virtualization.models import Cluster, ClusterGroup\n'), ((10259, 10278), 'django.utils.translation.gettext', '_', (['"""Cluster groups"""'], {}), "('Cluster groups')\n", (10260, 10278), True, 'from django.utils.translation import gettext as _\n'), ((10352, 10373), 'virtualization.models.Cluster.objects.all', 'Cluster.objects.all', ([], {}), '()\n', (10371, 10373), False, 'from virtualization.models import Cluster, ClusterGroup\n'), ((10413, 10426), 'django.utils.translation.gettext', '_', (['"""Clusters"""'], {}), "('Clusters')\n", (10414, 10426), True, 'from django.utils.translation import gettext as _\n'), ((10505, 10530), 'tenancy.models.TenantGroup.objects.all', 'TenantGroup.objects.all', ([], {}), '()\n', (10528, 10530), False, 'from tenancy.models import Tenant, TenantGroup\n'), ((10570, 10588), 'django.utils.translation.gettext', '_', (['"""Tenant groups"""'], {}), "('Tenant groups')\n", (10571, 10588), True, 'from django.utils.translation import gettext as _\n'), ((10661, 10681), 'tenancy.models.Tenant.objects.all', 'Tenant.objects.all', ([], {}), '()\n', (10679, 10681), False, 'from tenancy.models import Tenant, TenantGroup\n'), ((10721, 10732), 'django.utils.translation.gettext', '_', (['"""Tenant"""'], {}), "('Tenant')\n", (10722, 10732), True, 'from django.utils.translation import gettext as _\n'), ((10886, 10895), 'django.utils.translation.gettext', '_', (['"""Tags"""'], {}), "('Tags')\n", (10887, 10895), True, 'from django.utils.translation import gettext as _\n'), ((11088, 11122), 'django.utils.translation.gettext', '_', (['"""Has local config context data"""'], {}), "('Has local config context data')\n", (11089, 11122), True, 'from django.utils.translation import gettext as _\n'), ((11139, 11188), 'utilities.forms.StaticSelect2', 'StaticSelect2', ([], {'choices': 'BOOLEAN_WITH_BLANK_CHOICES'}), '(choices=BOOLEAN_WITH_BLANK_CHOICES)\n', (11152, 11188), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((12159, 12175), 'django.forms.Textarea', 'forms.Textarea', ([], {}), '()\n', (12173, 12175), False, 'from django import forms\n'), ((12376, 12387), 'django.utils.translation.gettext', '_', (['"""Search"""'], {}), "('Search')\n", (12377, 12387), True, 'from django.utils.translation import gettext as _\n'), ((12473, 12483), 'django.utils.translation.gettext', '_', (['"""After"""'], {}), "('After')\n", (12474, 12483), True, 'from django.utils.translation import gettext as _\n'), ((12500, 12516), 'utilities.forms.DateTimePicker', 'DateTimePicker', ([], {}), '()\n', (12514, 12516), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((12603, 12614), 'django.utils.translation.gettext', '_', (['"""Before"""'], {}), "('Before')\n", (12604, 12614), True, 'from django.utils.translation import gettext as _\n'), ((12631, 12647), 'utilities.forms.DateTimePicker', 'DateTimePicker', ([], {}), '()\n', (12645, 12647), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((12724, 12742), 'django.contrib.auth.models.User.objects.all', 'User.objects.all', ([], {}), '()\n', (12740, 12742), False, 'from django.contrib.auth.models import User\n'), ((12782, 12791), 'django.utils.translation.gettext', '_', (['"""User"""'], {}), "('User')\n", (12783, 12791), True, 'from django.utils.translation import gettext as _\n'), ((12808, 12854), 'utilities.forms.APISelectMultiple', 'APISelectMultiple', ([], {'api_url': '"""/api/users/users/"""'}), "(api_url='/api/users/users/')\n", (12825, 12854), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((12964, 12989), 'django.contrib.contenttypes.models.ContentType.objects.all', 'ContentType.objects.all', ([], {}), '()\n', (12987, 12989), False, 'from django.contrib.contenttypes.models import ContentType\n'), ((13029, 13045), 'django.utils.translation.gettext', '_', (['"""Object Type"""'], {}), "('Object Type')\n", (13030, 13045), True, 'from django.utils.translation import gettext as _\n'), ((13062, 13117), 'utilities.forms.APISelectMultiple', 'APISelectMultiple', ([], {'api_url': '"""/api/extras/content-types/"""'}), "(api_url='/api/extras/content-types/')\n", (13079, 13117), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((13193, 13234), 'utilities.forms.add_blank_choice', 'add_blank_choice', (['JournalEntryKindChoices'], {}), '(JournalEntryKindChoices)\n', (13209, 13234), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((13275, 13290), 'utilities.forms.StaticSelect2', 'StaticSelect2', ([], {}), '()\n', (13288, 13290), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((13467, 13478), 'django.utils.translation.gettext', '_', (['"""Search"""'], {}), "('Search')\n", (13468, 13478), True, 'from django.utils.translation import gettext as _\n'), ((13561, 13571), 'django.utils.translation.gettext', '_', (['"""After"""'], {}), "('After')\n", (13562, 13571), True, 'from django.utils.translation import gettext as _\n'), ((13588, 13604), 'utilities.forms.DateTimePicker', 'DateTimePicker', ([], {}), '()\n', (13602, 13604), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((13688, 13699), 'django.utils.translation.gettext', '_', (['"""Before"""'], {}), "('Before')\n", (13689, 13699), True, 'from django.utils.translation import gettext as _\n'), ((13716, 13732), 'utilities.forms.DateTimePicker', 'DateTimePicker', ([], {}), '()\n', (13730, 13732), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((13787, 13830), 'utilities.forms.add_blank_choice', 'add_blank_choice', (['ObjectChangeActionChoices'], {}), '(ObjectChangeActionChoices)\n', (13803, 13830), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((13871, 13886), 'utilities.forms.StaticSelect2', 'StaticSelect2', ([], {}), '()\n', (13884, 13886), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((13957, 13975), 'django.contrib.auth.models.User.objects.all', 'User.objects.all', ([], {}), '()\n', (13973, 13975), False, 'from django.contrib.auth.models import User\n'), ((14015, 14024), 'django.utils.translation.gettext', '_', (['"""User"""'], {}), "('User')\n", (14016, 14024), True, 'from django.utils.translation import gettext as _\n'), ((14041, 14087), 'utilities.forms.APISelectMultiple', 'APISelectMultiple', ([], {'api_url': '"""/api/users/users/"""'}), "(api_url='/api/users/users/')\n", (14058, 14087), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n'), ((14196, 14221), 'django.contrib.contenttypes.models.ContentType.objects.all', 'ContentType.objects.all', ([], {}), '()\n', (14219, 14221), False, 'from django.contrib.contenttypes.models import ContentType\n'), ((14261, 14277), 'django.utils.translation.gettext', '_', (['"""Object Type"""'], {}), "('Object Type')\n", (14262, 14277), True, 'from django.utils.translation import gettext as _\n'), ((14294, 14349), 'utilities.forms.APISelectMultiple', 'APISelectMultiple', ([], {'api_url': '"""/api/extras/content-types/"""'}), "(api_url='/api/extras/content-types/')\n", (14311, 14349), False, 'from utilities.forms import add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, CommentField, ContentTypeMultipleChoiceField, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES\n')]