mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-16 12:12:53 -06:00
#4416: Add bulk_add view for InventoryItems
This commit is contained in:
parent
7e3e18faea
commit
e4b5045ec7
@ -3372,6 +3372,165 @@ class DeviceBayCSVForm(CSVModelForm):
|
|||||||
self.fields['installed_device'].queryset = Interface.objects.none()
|
self.fields['installed_device'].queryset = Interface.objects.none()
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Inventory items
|
||||||
|
#
|
||||||
|
|
||||||
|
class InventoryItemForm(BootstrapMixin, forms.ModelForm):
|
||||||
|
device = DynamicModelChoiceField(
|
||||||
|
queryset=Device.objects.prefetch_related('device_type__manufacturer')
|
||||||
|
)
|
||||||
|
manufacturer = DynamicModelChoiceField(
|
||||||
|
queryset=Manufacturer.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
tags = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=Tag.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = InventoryItem
|
||||||
|
fields = [
|
||||||
|
'name', 'device', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'tags',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemCreateForm(BootstrapMixin, forms.Form):
|
||||||
|
device = DynamicModelChoiceField(
|
||||||
|
queryset=Device.objects.prefetch_related('device_type__manufacturer')
|
||||||
|
)
|
||||||
|
name_pattern = ExpandableNameField(
|
||||||
|
label='Name'
|
||||||
|
)
|
||||||
|
manufacturer = DynamicModelChoiceField(
|
||||||
|
queryset=Manufacturer.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
part_id = forms.CharField(
|
||||||
|
max_length=50,
|
||||||
|
required=False,
|
||||||
|
label='Part ID'
|
||||||
|
)
|
||||||
|
serial = forms.CharField(
|
||||||
|
max_length=50,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
asset_tag = forms.CharField(
|
||||||
|
max_length=50,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=100,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemCSVForm(CSVModelForm):
|
||||||
|
device = CSVModelChoiceField(
|
||||||
|
queryset=Device.objects.all(),
|
||||||
|
to_field_name='name'
|
||||||
|
)
|
||||||
|
manufacturer = CSVModelChoiceField(
|
||||||
|
queryset=Manufacturer.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = InventoryItem
|
||||||
|
fields = InventoryItem.csv_headers
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemBulkCreateForm(
|
||||||
|
form_from_model(InventoryItem, ['manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered', 'tags']),
|
||||||
|
DeviceBulkAddComponentForm
|
||||||
|
):
|
||||||
|
tags = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=Tag.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemBulkEditForm(BootstrapMixin, BulkEditForm):
|
||||||
|
pk = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=InventoryItem.objects.all(),
|
||||||
|
widget=forms.MultipleHiddenInput()
|
||||||
|
)
|
||||||
|
device = DynamicModelChoiceField(
|
||||||
|
queryset=Device.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
manufacturer = DynamicModelChoiceField(
|
||||||
|
queryset=Manufacturer.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
part_id = forms.CharField(
|
||||||
|
max_length=50,
|
||||||
|
required=False,
|
||||||
|
label='Part ID'
|
||||||
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=100,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
nullable_fields = [
|
||||||
|
'manufacturer', 'part_id', 'description',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemFilterForm(BootstrapMixin, forms.Form):
|
||||||
|
model = InventoryItem
|
||||||
|
q = forms.CharField(
|
||||||
|
required=False,
|
||||||
|
label='Search'
|
||||||
|
)
|
||||||
|
region = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=Region.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
required=False,
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
value_field="slug",
|
||||||
|
filter_for={
|
||||||
|
'site': 'region'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
site = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=Site.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
required=False,
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
value_field="slug",
|
||||||
|
filter_for={
|
||||||
|
'device_id': 'site'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
device_id = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=Device.objects.all(),
|
||||||
|
required=False,
|
||||||
|
label='Device'
|
||||||
|
)
|
||||||
|
manufacturer = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=Manufacturer.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
value_field="slug",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
discovered = forms.NullBooleanField(
|
||||||
|
required=False,
|
||||||
|
widget=StaticSelect2(
|
||||||
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
|
)
|
||||||
|
)
|
||||||
|
tag = TagFilterField(model)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Cables
|
# Cables
|
||||||
#
|
#
|
||||||
@ -3919,155 +4078,6 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Inventory items
|
|
||||||
#
|
|
||||||
|
|
||||||
class InventoryItemForm(BootstrapMixin, forms.ModelForm):
|
|
||||||
device = DynamicModelChoiceField(
|
|
||||||
queryset=Device.objects.prefetch_related('device_type__manufacturer')
|
|
||||||
)
|
|
||||||
manufacturer = DynamicModelChoiceField(
|
|
||||||
queryset=Manufacturer.objects.all(),
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
tags = DynamicModelMultipleChoiceField(
|
|
||||||
queryset=Tag.objects.all(),
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = InventoryItem
|
|
||||||
fields = [
|
|
||||||
'name', 'device', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'tags',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemCreateForm(BootstrapMixin, forms.Form):
|
|
||||||
device = DynamicModelChoiceField(
|
|
||||||
queryset=Device.objects.prefetch_related('device_type__manufacturer')
|
|
||||||
)
|
|
||||||
name_pattern = ExpandableNameField(
|
|
||||||
label='Name'
|
|
||||||
)
|
|
||||||
manufacturer = DynamicModelChoiceField(
|
|
||||||
queryset=Manufacturer.objects.all(),
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
part_id = forms.CharField(
|
|
||||||
max_length=50,
|
|
||||||
required=False,
|
|
||||||
label='Part ID'
|
|
||||||
)
|
|
||||||
serial = forms.CharField(
|
|
||||||
max_length=50,
|
|
||||||
required=False,
|
|
||||||
)
|
|
||||||
asset_tag = forms.CharField(
|
|
||||||
max_length=50,
|
|
||||||
required=False,
|
|
||||||
)
|
|
||||||
description = forms.CharField(
|
|
||||||
max_length=100,
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemCSVForm(CSVModelForm):
|
|
||||||
device = CSVModelChoiceField(
|
|
||||||
queryset=Device.objects.all(),
|
|
||||||
to_field_name='name'
|
|
||||||
)
|
|
||||||
manufacturer = CSVModelChoiceField(
|
|
||||||
queryset=Manufacturer.objects.all(),
|
|
||||||
to_field_name='name',
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = InventoryItem
|
|
||||||
fields = InventoryItem.csv_headers
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemBulkEditForm(BootstrapMixin, BulkEditForm):
|
|
||||||
pk = forms.ModelMultipleChoiceField(
|
|
||||||
queryset=InventoryItem.objects.all(),
|
|
||||||
widget=forms.MultipleHiddenInput()
|
|
||||||
)
|
|
||||||
device = DynamicModelChoiceField(
|
|
||||||
queryset=Device.objects.all(),
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
manufacturer = DynamicModelChoiceField(
|
|
||||||
queryset=Manufacturer.objects.all(),
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
part_id = forms.CharField(
|
|
||||||
max_length=50,
|
|
||||||
required=False,
|
|
||||||
label='Part ID'
|
|
||||||
)
|
|
||||||
description = forms.CharField(
|
|
||||||
max_length=100,
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
nullable_fields = [
|
|
||||||
'manufacturer', 'part_id', 'description',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemFilterForm(BootstrapMixin, forms.Form):
|
|
||||||
model = InventoryItem
|
|
||||||
q = forms.CharField(
|
|
||||||
required=False,
|
|
||||||
label='Search'
|
|
||||||
)
|
|
||||||
region = DynamicModelMultipleChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
to_field_name='slug',
|
|
||||||
required=False,
|
|
||||||
widget=APISelectMultiple(
|
|
||||||
value_field="slug",
|
|
||||||
filter_for={
|
|
||||||
'site': 'region'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
site = DynamicModelMultipleChoiceField(
|
|
||||||
queryset=Site.objects.all(),
|
|
||||||
to_field_name='slug',
|
|
||||||
required=False,
|
|
||||||
widget=APISelectMultiple(
|
|
||||||
value_field="slug",
|
|
||||||
filter_for={
|
|
||||||
'device_id': 'site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
device_id = DynamicModelMultipleChoiceField(
|
|
||||||
queryset=Device.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label='Device'
|
|
||||||
)
|
|
||||||
manufacturer = DynamicModelMultipleChoiceField(
|
|
||||||
queryset=Manufacturer.objects.all(),
|
|
||||||
to_field_name='slug',
|
|
||||||
required=False,
|
|
||||||
widget=APISelect(
|
|
||||||
value_field="slug",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
discovered = forms.NullBooleanField(
|
|
||||||
required=False,
|
|
||||||
widget=StaticSelect2(
|
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
|
||||||
)
|
|
||||||
)
|
|
||||||
tag = TagFilterField(model)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Virtual chassis
|
# Virtual chassis
|
||||||
#
|
#
|
||||||
|
@ -326,6 +326,7 @@ urlpatterns = [
|
|||||||
path('inventory-items/<int:pk>/edit/', views.InventoryItemEditView.as_view(), name='inventoryitem_edit'),
|
path('inventory-items/<int:pk>/edit/', views.InventoryItemEditView.as_view(), name='inventoryitem_edit'),
|
||||||
path('inventory-items/<int:pk>/delete/', views.InventoryItemDeleteView.as_view(), name='inventoryitem_delete'),
|
path('inventory-items/<int:pk>/delete/', views.InventoryItemDeleteView.as_view(), name='inventoryitem_delete'),
|
||||||
path('inventory-items/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='inventoryitem_changelog', kwargs={'model': InventoryItem}),
|
path('inventory-items/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='inventoryitem_changelog', kwargs={'model': InventoryItem}),
|
||||||
|
path('devices/inventory-items/add/', views.DeviceBulkAddInventoryItemView.as_view(), name='device_bulk_add_inventoryitem'),
|
||||||
|
|
||||||
# Cables
|
# Cables
|
||||||
path('cables/', views.CableListView.as_view(), name='cable_list'),
|
path('cables/', views.CableListView.as_view(), name='cable_list'),
|
||||||
|
@ -1859,6 +1859,17 @@ class DeviceBulkAddDeviceBayView(BulkComponentCreateView):
|
|||||||
default_return_url = 'dcim:device_list'
|
default_return_url = 'dcim:device_list'
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceBulkAddInventoryItemView(BulkComponentCreateView):
|
||||||
|
parent_model = Device
|
||||||
|
parent_field = 'device'
|
||||||
|
form = forms.InventoryItemBulkCreateForm
|
||||||
|
queryset = InventoryItem.objects.all()
|
||||||
|
model_form = forms.InventoryItemForm
|
||||||
|
filterset = filters.DeviceFilterSet
|
||||||
|
table = tables.DeviceTable
|
||||||
|
default_return_url = 'dcim:device_list'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Cables
|
# Cables
|
||||||
#
|
#
|
||||||
|
@ -74,6 +74,9 @@
|
|||||||
{% if perms.dcim.add_devicebay %}
|
{% if perms.dcim.add_devicebay %}
|
||||||
<li><a href="{% url 'dcim:devicebay_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Device Bays</a></li>
|
<li><a href="{% url 'dcim:devicebay_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Device Bays</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if perms.dcim.add_inventoryitem %}
|
||||||
|
<li><a href="{% url 'dcim:inventoryitem_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Inventory Items</a></li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
{% if perms.dcim.add_interface %}<li><a href="{% url 'dcim:device_bulk_add_interface' %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="formaction">Interfaces</a></li>{% endif %}
|
{% if perms.dcim.add_interface %}<li><a href="{% url 'dcim:device_bulk_add_interface' %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="formaction">Interfaces</a></li>{% endif %}
|
||||||
{% if perms.dcim.add_rearport %}<li><a href="{% url 'dcim:device_bulk_add_rearport' %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="formaction">Rear Ports</a></li>{% endif %}
|
{% if perms.dcim.add_rearport %}<li><a href="{% url 'dcim:device_bulk_add_rearport' %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="formaction">Rear Ports</a></li>{% endif %}
|
||||||
{% if perms.dcim.add_devicebay %}<li><a href="{% url 'dcim:device_bulk_add_devicebay' %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="formaction">Device Bays</a></li>{% endif %}
|
{% if perms.dcim.add_devicebay %}<li><a href="{% url 'dcim:device_bulk_add_devicebay' %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="formaction">Device Bays</a></li>{% endif %}
|
||||||
|
{% if perms.dcim.add_inventoryitem %}<li><a href="{% url 'dcim:device_bulk_add_inventoryitem' %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="formaction">Inventory Items</a></li>{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Loading…
Reference in New Issue
Block a user