{"id":48744768,"url":"https://github.com/ArnesSI/netbox-inventory","last_synced_at":"2026-04-28T07:00:54.212Z","repository":{"id":61845989,"uuid":"523290077","full_name":"ArnesSI/netbox-inventory","owner":"ArnesSI","description":"Manage your hardware inventory in NetBox","archived":false,"fork":false,"pushed_at":"2026-04-07T09:04:33.000Z","size":1686,"stargazers_count":297,"open_issues_count":21,"forks_count":38,"subscribers_count":21,"default_branch":"master","last_synced_at":"2026-04-07T11:11:36.374Z","etag":null,"topics":["netbox-plugin"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ArnesSI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-08-10T09:58:32.000Z","updated_at":"2026-04-07T09:04:37.000Z","dependencies_parsed_at":"2023-12-25T04:32:22.236Z","dependency_job_id":"45a3e72c-1471-48d9-adf5-20a9053440ea","html_url":"https://github.com/ArnesSI/netbox-inventory","commit_stats":{"total_commits":300,"total_committers":10,"mean_commits":30.0,"dds":"0.10666666666666669","last_synced_commit":"ea95687b82be0e34451fc2247851a45b8ddabe95"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"purl":"pkg:github/ArnesSI/netbox-inventory","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArnesSI%2Fnetbox-inventory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArnesSI%2Fnetbox-inventory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArnesSI%2Fnetbox-inventory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArnesSI%2Fnetbox-inventory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ArnesSI","download_url":"https://codeload.github.com/ArnesSI/netbox-inventory/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArnesSI%2Fnetbox-inventory/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32370030,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-27T20:07:02.737Z","status":"online","status_checked_at":"2026-04-28T02:00:07.250Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["netbox-plugin"],"created_at":"2026-04-12T10:00:46.180Z","updated_at":"2026-04-28T07:00:54.205Z","avatar_url":"https://github.com/ArnesSI.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# NetBox Inventory Plugin\n\nA [Netbox](https://github.com/netbox-community/netbox) plugin for hardware inventory.\n\n## Features\n\nKeep track of your hardware, whether it is installed or in storage. You can\ndefine assets that represent hardware that can be used as a device, module, inventory item or rack in NetBox.\n\nEach asset can have a storage location defined, when not in use. You can assign\nan asset to a device, module or inventory item. The plugin can keep serial number\nand asset tag between asset and device, module, inventory item or rack in sync if\nenabled in settings.\n\nOn Site and Location detail views there is a new tab Assets that can show assets\nthat are stored or installed at that location or both. Rack details view also has\na tab for installed Assets. This provides a unified view of all assets at a given\nlocation.\n\nTo properly support inventory items (that are used in NetBox to model SFP and\nsimilar modules) the plugin defines inventory item types that are equivalent to\ndevice types and module types. \n\nInventory item types can be assigned into inventory item groups. On a group detail\nview you have an overview of the number of contained assets broken down by asset\nstatus or inventory item type and status. This way you can quickly see how many\nof a certain type of hardware you still have spare.\n\nInventory item groups can be nested, so you can for example model all pluggables\nas one top-level group with child groups for SFP+ modules, SFP28 modules and so\non.\n\n### Bulk add asset tag generator\n\nWhen creating multiple assets via **Assets \u003e Add multiple**, you can now generate\n`asset_tag` values from a pattern.\n\n* Use the **Asset tag pattern** field (for example: `ASSET-[1-3]`).\n* The pattern must expand to the same number of values as **count**.\n* If no pattern is provided, bulk add behaves as before and creates assets without\n  generated asset tags.\n\n\u003e [!NOTE]\n\u003e Pattern expansion follows NetBox's alphanumeric expansion behavior.\n\u003e Example: `ASSET-[001-003]` expands to `ASSET-1`, `ASSET-2`, `ASSET-3`.\n\n### Automatic management of asset status\n\nEach asset has a status attribute that can indicate use of the asset. These\nstatuses can be set as needed by each NetBox installation.\n\nTwo statuses can have a special meaning. One to indicate asset is in storage and one\nto indicate asset is in use.\n\nnetbox_inventory can automatically set status to the value specified in\n`used_status_name` configuration item when an asset is assigned to a device, module\nor inventory item.\n\nWhen you remove an asset from device, module or inventory item the plugin will set\nasset status to `stored_status_name` configuration item.\n\nTo disable automatically changing status, set these two config parameters to `None`.\n\n### Prevent unwanted changes for tagged assets\n\nPast versions of netbox-inventory contained functionality to prevent users \nfrom making changes to assets that had a specific tag applied. The idea is \nthat an external system uses some assets stored in netbox-inventory, and you \nwant to prevent accidental changes to data directly in the NetBox web \ninterface. Only that external system should modify the data.\n\nThis functionality was removed in netbox-inventory 2.5.1 and newer. The same \nfunction can be achieved using NetBox's [Custom Validation rules](https://netboxlabs.com/docs/netbox/customization/custom-validation).\n\nHere is an example that prevents changing `serial` and `asset_tag` fields for \nassets that have the `no-edit` tag applied. Deletion of these assets is also \nprevented. Restrictions apply only to web interface changes. Deletions and \nmodifications via API are possible.\n\n\u003cdetails\u003e\n\u003csummary\u003eAsset validator example\u003c/summary\u003e\n\n```py\nfrom extras.validators import CustomValidator\nfrom utilities.data import shallow_compare_dict\n\n\nclass TagEditProtector(CustomValidator):\n    def __init__(self, protection_tag, protected_fields=None):\n        super().__init__(validation_rules=None)\n        self.protection_tag = protection_tag\n        self.protected_fields = protected_fields\n\n    def validate(self, instance, request):\n        # permit changes via API\n        if request and request.path.startswith('/api/'):\n            return\n        # permit changes via import\n        if request and '/import/' in request.path:\n            return\n        # see ChangeLoggingMixin.snapshot()\n        exclude = [\n            'last_updated',\n        ]\n        if not instance.pk:\n            # creating new object\n            return\n        if self.protection_tag not in instance.tags.all().values_list('slug', flat=True):\n            # if not tagged with protection_tag, no limitations\n            return\n        fail_msg = f'Cannot change {instance}. Protected by tag {self.protection_tag}'\n        violation = None\n        if not self.protected_fields:\n            # consider all fields protected\n            violation = fail_msg\n        else:\n            # Get fields that were changed\n            prechange_data = instance._prechange_snapshot\n            postchange_data = instance.serialize_object(exclude=exclude)\n            diff = shallow_compare_dict(prechange_data, postchange_data)\n            violated_fields = set(diff.keys()).intersection(self.protected_fields)\n            if violated_fields:\n                violation = dict(map(lambda f: (f, fail_msg), violated_fields))\n        if violation:\n            self.fail(violation)\n\n\nclass TagDeleteProtector(CustomValidator):\n    def __init__(self, protection_tag):\n        super().__init__(validation_rules=None)\n        self.protection_tag = protection_tag\n\n    def validate(self, instance, request):\n        if request and request.path.startswith('/api/'):\n            return\n        if self.protection_tag not in instance.tags.all().values_list('slug', flat=True):\n            # if not tagged with protection_tag, no limitations\n            return\n        self.fail(f'Cannot delete {instance}. Protected by tag {self.protection_tag}')\n\n\nCUSTOM_VALIDATORS = {\n    'netbox_inventory.asset': [\n        TagEditProtector('no-edit', ('serial', 'asset_tag')),\n    ],\n}\n\nPROTECTION_RULES = {\n    'netbox_inventory.asset': [\n        TagDeleteProtector('no-edit'),\n    ]\n}\n```\n\u003c/details\u003e\n\nPlace the above code snippet into your NetBox configuration file and restart \nthe NetBox web and worker processes.\n\nYou can of course modify the above example to suit your needs.\n\n### Audit\n\nAudit flows can be defined to audit the inventory on site. This feature is not limited\nto assets, it can be used to audit any object managed in NetBox.\n\n* **Audit Flow Pages** allow the definition of user views that list specific NetBox\n  objects. These can be filtered by object type and field values.\n* **Audit Flows** group multiple Audit Flow Pages into a single flow. A flow can be\n  initiated from a location type object (e.g. a `Location` or `Site`) using the\n  **[Audit]** button on its detail page. The audit flow will then display all audit flow\n  pages and their defined NetBox objects, restricted to the location for which the flow\n  is running.\n* **Audit Trails** document when an object has been verified to be in the specified\n  location. An audit trail can either be created directly when running an audit flow, or\n  imported from other systems using the API or an import form.\n* **Audit Trail Sources** can be used to optionally identify the source of an audit\n  trail. This option is only available when importing audit trails via the API or Import\n  form.\n\n#### Required Permissions\n\nTo run an audit flow, users need the `run` permission on the specific audit flow object.\nView permissions are also required for the object from which the audit flow is initiated\n(e.g. the `Site` or `Location`).\n\nAudited objects within the audit flow can be viewed without additional permissions.\nHowever, permissions are required to add, edit, or delete audited objects.\n\nTo mark an object as seen (i.e. to create an audit trail), the `add` and `delete`\npermissions should be granted on the audit trail model.\n\n#### Creating Audit Trails\n\nEach row of an audit flow page table begins with a button to mark an object as seen.\nClicking this button creates an audit trail for documentation. Bulk marking of multiple\nobjects as seen is also provided.\n\nHowever, there is a way to speed up this process even more: The quick search input field\non each page automatically gets the focus. Entering values into it will trigger the\nregular quick search. When the form is submitted (e.g. by hitting `[Enter]`), the value\nwill be processed using the object's filterset:\n\n1. If only one result remains after filtering the current page, this object is\n   automatically marked as seen.\n2. If there is only one result after filtering all objects of the processed object type,\n   the user will be redirected to it's edit form. It is assumed that the location of the\n   object is not correctly documented (e.g. the object has been moved). After submitting\n   the changes, the user is returned to the audit flow page and can now mark it as seen.\n3. If no matching object is found, a warning is displayed. The user must manually create\n   the object.\n\n#### Audit Reports\n\nAt this time, this plugin does not include any reporting on the current audit status of\nobjects, as simple-looking implementations can lead to many different ways of evaluating\nand aggregating the data for different use cases. However, most, if not all,\nimplementations can be done with a [custom script][nbScript]:\n\n[nbScript]: https://netboxlabs.com/docs/netbox/en/stable/customization/custom-scripts/\n\n```Python\nfrom django.db.models import OuterRef, Q, Subquery\n\nfrom core.models import ObjectType\nfrom dcim.models import Device, Module\nfrom extras.scripts import Script\n\nfrom netbox_inventory.models import Asset, AuditTrail\n\n\nclass AuditReportMissing(Script):\n    description = 'Check for missing audit trails of assets'\n\n    def test_missing_audit_assets(self) -\u003e None:\n        queryset = Asset.objects.annotate(\n            last_audit_date=Subquery(\n                AuditTrail.objects.filter(\n                    Q(\n                        object_type=ObjectType.objects.get_for_model(Asset),\n                        object_id=OuterRef('pk'),\n                    )\n                    # Also, check for the assigned device or module of an Asset.\n                    | Q(\n                        object_type=ObjectType.objects.get_for_model(Device),\n                        object_id=OuterRef('device__pk'),\n                    )\n                    | Q(\n                        object_type=ObjectType.objects.get_for_model(Module),\n                        object_id=OuterRef('module__pk'),\n                    )\n                )\n                .order_by('-created')\n                .values_list('created', flat=True)[:1]\n            )\n        )\n\n        for asset in queryset.filter(last_audit_date__isnull=True):\n            self.log_warning('No recent audit for object found.', obj=asset)\n```\n\n## Compatibility\n\nThis plugin requires netbox version 4.5 to work. Older versions of the plugin\nsupport older netbox version as per table below:\n\n| NetBox Version | Plugin Version |\n|----------------|----------------|\n|       3.7      |      1.6.x     |\n|       4.0      |      2.0.x     |\n|       4.1      |  2.1.x,2.2.x   |\n|       4.2      |      2.3.x     |\n|       4.3      |      2.4.0     |\n|       4.4      |    \u003e=2.4.1     |\n|       4.5      |      2.5.x     |\n\n## Installing\n\nReview [official Netbox plugin documentation](https://docs.netbox.dev/en/stable/plugins/#installing-plugins) for installation instructions.\n\nYou install the plugin from pypi with pip. Make sure you activate Netbox's virtual\nenvironment first:\n\n```bash\n$ source /opt/netbox/venv/bin/activate\n(venv) $ pip install netbox-inventory\n```\n\nFor adding to a NetBox Docker setup see\n[the general instructions for using netbox-docker with plugins](https://github.com/netbox-community/netbox-docker/wiki/Using-Netbox-Plugins).\n\nYou can install a development version directly from GitHub:\n\n```bash\npip install https://github.com/ArnesSI/netbox-inventory/archive/master.tar.gz\n```\n\nor by adding to your `local_requirements.txt` or `plugin_requirements.txt` (netbox-docker):\n\n```bash\nhttps://github.com/ArnesSI/netbox-inventory/archive/master.tar.gz\n```\n\nAfter installation, enable the plugin in `/opt/netbox/netbox/netbox/configuration.py`,\n or if you use netbox-docker, your `/configuration/plugins.py` file :\n\n```python\nPLUGINS = [\n    'netbox_inventory'\n]\n\nPLUGINS_CONFIG = {\n    \"netbox_inventory\": {},\n}\n```\n\nAvailable configuration settings you can use in `PLUGINS_CONFIG` are described\nbelow under [settings](#settings).\n\nThe last step is to apply database migrations and update netbox search index:\n\n```bash\n(venv) $ cd /opt/netbox/netbox/\n(venv) $ python3 manage.py migrate\n(venv) $ python3 manage.py reindex --lazy\n```\n\nIf you're running under netbox-docker, you can skip this as migrations and index updates are applied if needed automatically when you bring up the containers.\n\n### Settings\n\nIf you want to override the defaults for the plugin, you can do so in your via `/opt/netbox/netbox/netbox/configuration.py`,\n or if you use netbox-docker, your `/configuration/plugins.py` file :\n\n```python\nPLUGINS = [\n    'netbox_inventory'\n]\n\nPLUGINS_CONFIG = {\n    \"netbox_inventory\": {\n        # Example settings below, see \"Available settings\"\n        # in README.md for all possible settings\n        \"used_status_name\": \"used\",\n        \"stored_status_name\": \"stored\",\n        \"sync_hardware_serial_asset_tag\": True,\n    },\n}\n```\n\n#### Available settings\n\n| Setting | Default value | Description |\n|---------|---------------|-------------|\n| `top_level_menu` | `True`| Add netbox-inventory to the top level of netbox navigation menu under Inventory heading. If set to False the plugin will add a menu item under the Plugins menu item.\n| `used_status_name` | `'used'`| Status that indicates asset is in use. See \"Automatic management of asset status\" below for more info on this setting.\n| `used_additional_status_names` | `[]` (empty list) | List of statuses that are also considered as in use.\n| `stored_status_name` | `'stored'`| Status that indicates asset is in storage. See \"Automatic management of asset status\" below for more info on this setting.\n| `stored_additional_status_names` | `['retired',]`| List of statuses that are also considered as not in use by various filters.\n| `sync_hardware_serial_asset_tag` | `False` | When an asset is assigned or unassigned to a device, module or inventory item, update its serial number and asset tag to be in sync with the asset? For device and module device type or module type is also updated to match asset. For inventory items, manufacturer and part ID are updated to match asset. |\n| `asset_import_create_purchase` | `False` | When importing assets, automatically create any given purchase, delivery or supplier if it doesn't exist already |\n| `asset_import_create_device_type` | `False` | When importing a device type asset, automatically create manufacturer and/or device type if it doesn't exist |\n| `asset_import_create_module_type` | `False` | When importing a module type asset, automatically create manufacturer and/or module type if it doesn't exist |\n| `asset_import_create_inventoryitem_type` | `False` | When importing an inventory type asset, automatically create manufacturer and/or inventory item type if it doesn't exist |\n| `asset_import_create_rack_type` | `False` | When importing a rack type asset, automatically create manufacturer and/or rack type if it doesn't exist |\n| `asset_import_create_tenant` | `False` | When importing an asset, with owner or tenant, automatically create tenant if it doesn't exist |\n| `asset_custom_fields_search_filters` | `{}` | A dictionary of custom fields and lookup types that will be added to the search filters for assets. The dictionary is in the form of `{field: [lookup_type]}`. Example: `{'asset_mac': ['icontains', 'exact']}`. |\n| `asset_warranty_expire_warning_days` | `90` | Days from warranty expiration to show as warning in Warranty remaining field |\n| `prefill_asset_name_create_inventoryitem` | `False` | When hardware inventory item is created from an asset, prefill the InventoryItem name to match the asset name. |\n| `prefill_asset_tag_create_inventoryitem` | `False` | When hardware inventory item is created from an asset, prefill the tags to match the tags associated to the asset. |\n| `audit_window` | `240` | Defines a sliding timeframe starting from the current time in minutes. If an audit trail exists for a particular object in this window, it is marked as seen when an audit trail is run to avoid repeated actions. |\n\nYou can extend or define your own status choices for Asset, via [`FIELD_CHOICES`](https://docs.netbox.dev/en/stable/configuration/data-validation/#field_choices) setting in Netbox:\n\n```\nFIELD_CHOICES = {\n    'netbox_inventory.Asset.status+': (\n        ('repair', 'In repair', 'orange'),\n    ),\n}\n```\n\nIf you add more statuses, you should also adjust `used_additional_status_names` and `stored_additional_status_names` settings.\n\nThe possible colours can be found at [FIELD_CHOICES](https://netboxlabs.com/docs/netbox/configuration/data-validation/#field_choices).\n\n## Common questions\n\n### I'd like to attach documents to asset, purchase, supplier, etc\n\nNetbox inventory supports limited file attachments for its various models. You can add images to assets, inventory item types and that is it.\n\nIf you would like to attach various other documents to purchases, deliveries, suppliers... first ask yourself if you really need those documents in netbox or could you use some other tool that is possibly in use in your organization. Netbox itself is not great at managing documents. If you decide to manage documents outside netbox, you can probably still achieve some sort of integration by using [custom links feature](https://netboxlabs.com/docs/netbox/en/stable/customization/custom-links/) to link from a netbox inventory object directly to a document in your document system.\n\nIf you really want to store document in netbox itself, then consider using [netbox_attachments plugin](https://github.com/Kani999/netbox-attachments). Here is a sample netbox configuration that will allow adding documents to suppliers, purchases and deliveries:\n\n```python\nPLUGINS = [\n    'netbox_inventory',\n    'netbox_attachments',\n]\n\nPLUGINS_CONFIG = {\n    'netbox_attachments': {\n        'applied_scope': 'model',\n        'scope_filter': [\n            'netbox_inventory.supplier',\n            'netbox_inventory.purchase',\n            'netbox_inventory.delivery',\n        ],\n        'display_setting': {\n            \"netbox_inventory.supplier\": \"left_page\",\n            \"netbox_inventory.purchase\": \"full_width_page\",\n            \"netbox_inventory.delivery\": \"righ_page\",\n        },\n    },\n}\n```\n\nLook at [netbox-attachments](https://github.com/Kani999/netbox-attachments)\ndocumentation for more configuration examples.\n\nHere is what it looks like when viewing a purchase:\n\n![Example using netbox_attachments plugin](docs/img/netbox_attachments_example.png)\n\n## Models\n\nCurrent plugin data model:\n\n![Working Model](docs/img/data_model.drawio.png)\n\n## Screenshots\n\nAsset - List View\n\n![Asset - List View](docs/img/asset_list.png)\n\nAsset - Individual View\n\n![Asset - Individual View](docs/img/asset.png)\n\nAsset - Edit / Add View\n\n![Asset - Edit / Add View](docs/img/asset_edit.png)\n\nAsset - Lots of filtering options\n\n![Asset - Filters](docs/img/asset_filters.png)\n\nSuppliers - Individual View\n\n![Asset - Individual View](docs/img/supplier.png)\n\nInventory Item Type - List View\n\n![Asset - List View](docs/img/inventoryitem_type_list.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArnesSI%2Fnetbox-inventory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FArnesSI%2Fnetbox-inventory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArnesSI%2Fnetbox-inventory/lists"}