Repository: netbox-community/netbox

Issue:
'NoneType' object has no attribute '_base_manager'
### NetBox version

v3.0.1

### Python version

3.8

### Steps to Reproduce

Upgrade from 2.11.0  with git, after this

### Expected Behavior

Server Error
There was a problem with your request. Please contact an administrator.

The complete exception is provided below:

```
<class 'AttributeError'>

'NoneType' object has no attribute '_base_manager'

Python version: 3.8.10
NetBox version: 3.0.1
If further assistance is required, please post to the NetBox discussion forum on GitHub.
```

### Observed Behavior

What can I do?


Discussion:
> Upgrade from 2.11.0 with git, after this

This alone is not sufficient to reproduce the error. Under #7082 is was [suggested](https://github.com/netbox-community/netbox/issues/7082#issuecomment-911176019) that the error may be related to the existence of secrets prior to upgrade. (Note that v3.0 drops support for secrets entirely.) Can you confirm this on your installation?

Also, can you please provide the complete stack trace?
I was able to reproduce this by starting with a v2.11.12 install, creating a user key and secret, and then upgrading to v3.0.1. AFAICT it only affects installations which have an active changelog entry relating to a secret.
While we work on a fix for this, it's possible to work around this bug by deleting all changelog data relating to objects from the old secrets app in NetBox.

**This will delete all changelog data for all secrets, secret roles, user keys, and session keys.** If this data is important to you, either wait for the fix in v3.0.2, or make a copy of your database before applying the script below so that the data can be retrieved at a later date.

To delete all secrets changelog data, open the [NetBox shell](https://netbox.readthedocs.io/en/stable/administration/netbox-shell/) (`manage.py nbshell`) and run the following script:

```python
content_type_ids = ContentType.objects.filter(app_label='secrets').values_list('id', flat=True)
ObjectChange.objects.filter(changed_object_type__in=content_type_ids).delete()
```

You should see it return a total count of the changelog records which have been deleted, like this:

```
(123, {'extras.ObjectChange': 123})
```

At this point, NetBox should behave normally. It is not necessary to restart any services after deleting the data.
The root issue here is that latent changelog records referencing e.g. a Secret instance from v2.11 or earlier raise an exception when trying to resolve the related object into a Python instance.

While it may be possible to catch and suppress these exceptions, doing so would likely be hacky and error-prone. A more robust approach would be to introduce a database migration to simply delete the offending changelog records. While this would result in deletion of changelog data, the impact of this doing so be negligible given that these objects no longer "exist" in NetBox anyway.

Any arguments for or against?
So we had a quick discussion about this, couple of important things:

1. If someone else wants to hook into change logging in the future then if the plugin is removed or deleted this will pop up again
2. There are a few ways to handle this (getters around the object, checking for NoneTypes in the templates, etc), some of them aren't bulletproof
3. You only see this if you have used secrets in the past (probably recently) that has generated a change log

Just wanted to capture that here.

Resolving patch:
diff --git a/netbox/extras/migrations/0062_clear_secrets_changelog.py b/netbox/extras/migrations/0062_clear_secrets_changelog.py
new file mode 100644
--- /dev/null
+++ b/netbox/extras/migrations/0062_clear_secrets_changelog.py
@@ -0,0 +1,26 @@
+from django.db import migrations
+
+
+def clear_secrets_changelog(apps, schema_editor):
+    """
+    Delete all ObjectChange records referencing a model within the old secrets app (pre-v3.0).
+    """
+    ContentType = apps.get_model('contenttypes', 'ContentType')
+    ObjectChange = apps.get_model('extras', 'ObjectChange')
+
+    content_type_ids = ContentType.objects.filter(app_label='secrets').values_list('id', flat=True)
+    ObjectChange.objects.filter(changed_object_type__in=content_type_ids).delete()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('extras', '0061_extras_change_logging'),
+    ]
+
+    operations = [
+        migrations.RunPython(
+            code=clear_secrets_changelog,
+            reverse_code=migrations.RunPython.noop
+        ),
+    ]


Test patch: