diff --git a/src/netbox_slm/filters.py b/src/netbox_slm/filters.py index d92c8cb..3a56901 100644 --- a/src/netbox_slm/filters.py +++ b/src/netbox_slm/filters.py @@ -36,7 +36,7 @@ class SoftwareProductFilter(BaseFilter): class SoftwareProductVersionFilter(BaseFilter): name = django_filters.CharFilter( - lookup_expr="icontains", + lookup_expr="icontains", label="Version" ) # software_product_id = django_filters.ModelMultipleChoiceFilter( # queryset=SoftwareProduct.objects.all(), diff --git a/src/netbox_slm/forms.py b/src/netbox_slm/forms.py index 9d69420..388d553 100644 --- a/src/netbox_slm/forms.py +++ b/src/netbox_slm/forms.py @@ -13,6 +13,7 @@ from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareP from utilities.forms import ( BootstrapMixin, DynamicModelChoiceField, APISelect, DynamicModelMultipleChoiceField ) +from virtualization.models import VirtualMachine class SoftwareProductForm(BootstrapMixin, CustomFieldModelForm): @@ -33,7 +34,7 @@ class SoftwareProductForm(BootstrapMixin, CustomFieldModelForm): class Meta: model = SoftwareProduct - fields = ("name", "manufacturer",) # "tags") + fields = ("name", "manufacturer", "description",) # "tags") class SoftwareProductFilterForm(BootstrapMixin, CustomFieldModelFilterForm): @@ -134,16 +135,23 @@ class SoftwareProductInstallationForm(BootstrapMixin, CustomFieldModelForm): # 'device_types': 'device_type' # } ) + virtualmachine = DynamicModelChoiceField( + queryset=VirtualMachine.objects.all(), + required=False, + # initial_params={ + # 'device_types': 'device_type' + # } + ) software_product = DynamicModelChoiceField( queryset=SoftwareProduct.objects.all(), - required=False, + required=True, widget=APISelect( attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")} ), ) version = DynamicModelChoiceField( queryset=SoftwareProductVersion.objects.all(), - required=False, + required=True, widget=APISelect( attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproductversion-list")} ), @@ -161,7 +169,7 @@ class SoftwareProductInstallationForm(BootstrapMixin, CustomFieldModelForm): class Meta: model = SoftwareProductInstallation - fields = ("device", "software_product", "version",) # "tags") + fields = ("device", "virtualmachine", "software_product", "version",) # "tags") # def clean(self): # import pdb;pdb.set_trace() diff --git a/src/netbox_slm/migrations/0001_initial.py b/src/netbox_slm/migrations/0001_initial.py index 0cfe290..766339d 100644 --- a/src/netbox_slm/migrations/0001_initial.py +++ b/src/netbox_slm/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.8 on 2021-11-04 15:38 +# Generated by Django 3.2.8 on 2021-12-17 10:11 import django.core.serializers.json from django.db import migrations, models @@ -11,8 +11,9 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('dcim', '0133_port_colors'), + ('virtualization', '0023_virtualmachine_natural_ordering'), ('extras', '0062_clear_secrets_changelog'), + ('dcim', '0133_port_colors'), ] operations = [ @@ -24,7 +25,7 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=128)), - ('description', models.CharField(max_length=255)), + ('description', models.CharField(blank=True, max_length=255, null=True)), ('manufacturer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='software_products', to='dcim.manufacturer')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], @@ -47,4 +48,21 @@ class Migration(migrations.Migration): 'abstract': False, }, ), + migrations.CreateModel( + name='SoftwareProductInstallation', + fields=[ + ('created', models.DateField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), + ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='softwareproduct_installations', to='dcim.device')), + ('software_product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='software_products', to='netbox_slm.softwareproduct')), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ('version', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='softwareproduct_versions', to='netbox_slm.softwareproductversion')), + ('virtualmachine', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='softwareproduct_installations', to='virtualization.virtualmachine')), + ], + options={ + 'abstract': False, + }, + ), ] diff --git a/src/netbox_slm/migrations/0002_softwareproductinstallation.py b/src/netbox_slm/migrations/0002_softwareproductinstallation.py deleted file mode 100644 index 6ec95ca..0000000 --- a/src/netbox_slm/migrations/0002_softwareproductinstallation.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 3.2.8 on 2021-12-08 12:10 - -import django.core.serializers.json -from django.db import migrations, models -import django.db.models.deletion -import taggit.managers - - -class Migration(migrations.Migration): - - dependencies = [ - ('extras', '0062_clear_secrets_changelog'), - ('dcim', '0133_port_colors'), - ('netbox_slm', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='SoftwareProductInstallation', - fields=[ - ('created', models.DateField(auto_now_add=True, null=True)), - ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), - ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('device', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='softwareproduct_installations', to='dcim.device')), - ('software_product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='software_products', to='netbox_slm.softwareproduct')), - ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('version', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='softwareproduct_versions', to='netbox_slm.softwareproductversion')), - ], - options={ - 'abstract': False, - }, - ), - ] diff --git a/src/netbox_slm/models.py b/src/netbox_slm/models.py index 43b0677..f14365a 100644 --- a/src/netbox_slm/models.py +++ b/src/netbox_slm/models.py @@ -11,7 +11,7 @@ class SoftwareProduct(PrimaryModel): A SoftwareProduct represents ... """ name = models.CharField(max_length=128) - description = models.CharField(max_length=255) + description = models.CharField(max_length=255, null=True, blank=True) manufacturer = models.ForeignKey( to='dcim.Manufacturer', @@ -27,6 +27,9 @@ class SoftwareProduct(PrimaryModel): def get_absolute_url(self): return reverse("plugins:netbox_slm:softwareproduct", kwargs={"pk": self.pk}) + def get_installation_count(self): + return SoftwareProductInstallation.objects.filter(software_product_id=self.pk).count() + # @extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks') class SoftwareProductVersion(PrimaryModel): @@ -45,19 +48,26 @@ class SoftwareProductVersion(PrimaryModel): def get_absolute_url(self): return reverse("plugins:netbox_slm:softwareproductversion", kwargs={"pk": self.pk}) + def get_installation_count(self): + return SoftwareProductInstallation.objects.filter(version_id=self.pk).count() + # @extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks') class SoftwareProductInstallation(PrimaryModel): device = models.ForeignKey( to='dcim.Device', on_delete=models.PROTECT, - related_name='softwareproduct_installations' + related_name='softwareproduct_installations', + null=True, + blank=True + ) + virtualmachine = models.ForeignKey( + to='virtualization.VirtualMachine', + on_delete=models.PROTECT, + related_name='softwareproduct_installations', + null = True, + blank = True ) - # virtualmachine = models.ForeignKey( - # to='virtualization.VirtualMachine', - # on_delete=models.PROTECT, - # related_name='softwareproduct_installations' - # ) software_product = models.ForeignKey( to='netbox_slm.SoftwareProduct', on_delete=models.PROTECT, diff --git a/src/netbox_slm/tables.py b/src/netbox_slm/tables.py index 274b7ef..840d34c 100644 --- a/src/netbox_slm/tables.py +++ b/src/netbox_slm/tables.py @@ -13,6 +13,7 @@ class SoftwareProductTable(BaseTable): accessor=Accessor('manufacturer'), linkify=True ) + installations = tables.Column(accessor='get_installation_count', verbose_name='Installations') # tags = TagColumn( # url_name="plugins:netbox_dns:zone_list", @@ -24,12 +25,16 @@ class SoftwareProductTable(BaseTable): "pk", "name", "manufacturer", + "description", + "installations", # "tags", ) default_columns = ( "pk", "name", "manufacturer", + "description", + "installations", # "tags", ) @@ -38,7 +43,7 @@ class SoftwareProductVersionTable(BaseTable): """Table for displaying SoftwareProductVersion objects.""" pk = ToggleColumn() - name = tables.LinkColumn() + name = tables.LinkColumn(verbose_name='Version') software_product = tables.Column( accessor=Accessor('software_product'), linkify=True @@ -47,6 +52,7 @@ class SoftwareProductVersionTable(BaseTable): accessor=Accessor('software_product__manufacturer'), linkify=True ) + installations = tables.Column(accessor='get_installation_count', verbose_name='Installations') # tags = TagColumn( # url_name="plugins:netbox_dns:zone_list", @@ -59,6 +65,7 @@ class SoftwareProductVersionTable(BaseTable): "name", "software_product", "manufacturer", + "installations", # "tags", ) default_columns = ( @@ -66,6 +73,7 @@ class SoftwareProductVersionTable(BaseTable): "name", "software_product", "manufacturer", + "installations", # "tags", ) @@ -79,6 +87,10 @@ class SoftwareProductInstallationTable(BaseTable): accessor=Accessor('device'), linkify=True ) + virtualmachine = tables.Column( + accessor=Accessor('virtualmachine'), + linkify=True + ) software_product = tables.Column( accessor=Accessor('software_product'), linkify=True @@ -98,6 +110,7 @@ class SoftwareProductInstallationTable(BaseTable): "pk", "name", "device", + "virtualmachine", "software_product", "version", # "tags", @@ -105,6 +118,7 @@ class SoftwareProductInstallationTable(BaseTable): default_columns = ( "pk", "device", + "virtualmachine", "software_product", "version", # "tags",