Installing the App in Nautobot¶
This page covers install and configure for nautobot-contract-models.
Prerequisites¶
- Nautobot 3.0.0 or higher
- Database: PostgreSQL or MySQL
- Python 3.10+
Note
Check the compatibility matrix for the supported Nautobot version range.
Install Guide¶
The app is published on PyPI. Install with pip:
To make sure the app is reinstalled on Nautobot upgrades, add it to your local_requirements.txt:
Enable the App¶
Edit nautobot_config.py:
- Append
"nautobot_contract_models"toPLUGINS. - Optionally add a
"nautobot_contract_models"block toPLUGINS_CONFIG.
# In nautobot_config.py
PLUGINS = [
"nautobot_contract_models",
]
PLUGINS_CONFIG = {
"nautobot_contract_models": {
# Default window for the renewal-check Job and the home dashboard
# "Upcoming Renewals" panel. Defaults to 60 days.
"renewal_window_days": 60,
},
}
Then run migrations and collect static:
Restart the Nautobot web service AND the Celery worker:
The worker restart is important — newly-discovered Jobs won't appear until the worker re-reads the registry.
Verify the install¶
- Visit
/apps/installed-apps/and confirmnautobot_contract_modelsis listed. - Visit
/plugins/contracts/contracts/— you should see the (empty) contract list. - Visit
/jobs/and look under the Contracts group for five jobs:- Check upcoming renewals
- Find devices without contract coverage
- Monthly cost report
- Capture cost history snapshot
- Detect cost anomalies
App Configuration¶
| Setting | Default | Description |
|---|---|---|
renewal_window_days |
60 |
Days from today to look ahead. Drives the renewal-check Job's default and the Renewal Forecast home dashboard panel. |
hide_dlm_contracts_nav |
False |
When True AND nautobot-app-device-lifecycle-mgmt is installed, surgically removes DLM's Contracts group from the Device Lifecycle sidebar. Operator-controlled; off by default. See Coexistence with nautobot-app-device-lifecycle. |
Coexistence with nautobot-app-device-lifecycle¶
nautobot-app-device-lifecycle-mgmt (DLM) ships a ContractLCM model that overlaps with our Contract. Since v2026.5.11 the two plugins coexist cleanly in the same Nautobot. v2026.5.12 adds two opt-in features for operators who want our Contract to be the canonical contracts surface:
1. Migrate ContractLCM data into our model¶
Run the Migrate ContractLCM → Contract Job (under Apps → Jobs → Contracts):
- Apps → Jobs → "Migrate ContractLCM → Contract" — click the row, then Edit → check Enabled → Save. (Nautobot's job-permission default is disabled.)
- Click Run Job.
- Set
dry_run=Truefor the first invocation. Read the JobLogEntry output:- Counts:
migrated,skipped,assignments(devices converted intoContractAssignmentrows),warnings. - Per-row
[dry-run] Would migrate...lines. [unmapped]warnings for rows whosesupport_levelorcontract_typefree-text didn't match any known pattern. Fix the source values in DLM's UI, or accept that those fields land blank.
- Counts:
- Re-run with
dry_run=Falseto commit. - Re-run a third time — verify
migrated: 0(idempotency stamp prevents duplicates).
Each migrated ContractLCM is stamped with a custom field migrated_to_contract_models=True. Source rows are not deleted — operators delete from DLM's UI when comfortable that the migration is correct.
Job options:
| Variable | Default | Meaning |
|---|---|---|
dry_run |
True |
Log planned actions without writing. Always run dry first. |
default_billing_period |
Monthly |
DLM's ContractLCM.cost is a flat decimal with no cadence — we interpret it as recurring at this cadence. Set to Annual if your DLM contracts stored annual prices. |
provider_match_strategy |
Match by name; create ServiceProvider if missing |
Alternative: Match by name; skip the contract if no ServiceProvider matches. |
2. Hide DLM's Contracts sidebar group¶
After migration, set the opt-in flag:
# nautobot_config.py
PLUGINS_CONFIG = {
"nautobot_contract_models": {
"hide_dlm_contracts_nav": True,
},
}
Restart Nautobot. DLM's Contracts and Vendors sub-items disappear from the Device Lifecycle sidebar; Hardware Notices, Software Lifecycle, and Reports remain.
DLM's data, URLs (/plugins/nautobot-device-lifecycle-mgmt/contract/...), REST API, and DeviceContractLCM template-content panel on the Device detail page all keep working — only the sidebar nav is affected. Operators with scripts or external integrations hitting DLM's contract endpoints don't break.
Upgrading from pre-Phase-8¶
Migration 0007_contract_billing_period defaults every existing Contract to billing_period='monthly'. If you have annual or quarterly contracts already in the database, their recurring_cost will be interpreted as a monthly figure after upgrade — over-counting the burn rate panels by 12x (annual) or 3x (quarterly).
Two ways to fix:
Option 1 — bulk edit via the UI
- Visit
/plugins/contracts/contracts/?billing_period=monthly - Select contracts that should be annual / quarterly
- Click Edit Selected and change
billing_period
Option 2 — Django ORM (faster for many contracts)
# nautobot-server shell
from nautobot_contract_models.models import Contract
Contract.objects.filter(name__icontains="EA").update(billing_period="annual")
Contract.objects.filter(name__icontains="quarterly").update(billing_period="quarterly")
After the fix, run Capture cost history snapshot to refresh the trend baseline.
Static files¶
The plugin ships its own static CSS files for the Renewal Calendar, Action Required, and Cost History pages. nautobot-server collectstatic picks these up automatically; no additional configuration needed.
Removing the app¶
See Uninstall.