We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
User Dashboard can become permanently broken when misconfiguring DEFAULT_DASHBOARD
### Deployment Type

Self-hosted

### NetBox Version

v3.7.0

### Python Version

3.9

### Steps to Reproduce

1. User johndoe modifies their dashboard over the GUI
2. Administrator changes DEFAULT_DASHBOARD in configuration.py with a broken configuration (Assigned a wrong value in a bookmarks widget)
3. Bookmark widget looks fine without logging in since it won't load any data
4. After johndoe logs in, they reset their dashboard
5. Site crashes with an Field Error Exception since the dashboard is misconfigured
6. johndoe can't reset their dashboard anymore, even after the error in DEFAULT_DASHBOARD is corrected

### Expected Behavior

When resetting the dashboard, I would expect it to now always follow the changes of DEFAULT_DASHBOARD.

### Observed Behavior

Resetting the dashboard seems to copy the current state of DEFAULT_DASHBOARD. If that state is broken, a user cannot reset it anymore.
Only the main page with the dashboard crashes.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `netbox/extras/dashboard/utils.py`
Content:
```
1 import uuid
2 
3 from django.conf import settings
4 from django.core.exceptions import ObjectDoesNotExist
5 
6 from netbox.registry import registry
7 from extras.constants import DEFAULT_DASHBOARD
8 
9 __all__ = (
10     'get_dashboard',
11     'get_default_dashboard',
12     'get_widget_class',
13     'register_widget',
14 )
15 
16 
17 def register_widget(cls):
18     """
19     Decorator for registering a DashboardWidget class.
20     """
21     app_label = cls.__module__.split('.', maxsplit=1)[0]
22     label = f'{app_label}.{cls.__name__}'
23     registry['widgets'][label] = cls
24 
25     return cls
26 
27 
28 def get_widget_class(name):
29     """
30     Return a registered DashboardWidget class identified by its name.
31     """
32     try:
33         return registry['widgets'][name]
34     except KeyError:
35         raise ValueError(f"Unregistered widget class: {name}")
36 
37 
38 def get_dashboard(user):
39     """
40     Return the Dashboard for a given User if one exists, or generate a default dashboard.
41     """
42     if user.is_anonymous:
43         dashboard = get_default_dashboard()
44     else:
45         try:
46             dashboard = user.dashboard
47         except ObjectDoesNotExist:
48             # Create a dashboard for this user
49             dashboard = get_default_dashboard()
50             dashboard.user = user
51             dashboard.save()
52 
53     return dashboard
54 
55 
56 def get_default_dashboard():
57     from extras.models import Dashboard
58 
59     dashboard = Dashboard()
60     default_config = settings.DEFAULT_DASHBOARD or DEFAULT_DASHBOARD
61 
62     for widget in default_config:
63         id = str(uuid.uuid4())
64         dashboard.layout.append({
65             'id': id,
66             'w': widget['width'],
67             'h': widget['height'],
68             'x': widget.get('x'),
69             'y': widget.get('y'),
70         })
71         dashboard.config[id] = {
72             'class': widget['widget'],
73             'title': widget.get('title'),
74             'color': widget.get('color'),
75             'config': widget.get('config', {}),
76         }
77 
78     return dashboard
79
```

Path: `netbox/netbox/views/misc.py`
Content:
```
1 import re
2 from collections import namedtuple
3 
4 from django.conf import settings
5 from django.contrib.contenttypes.models import ContentType
6 from django.core.cache import cache
7 from django.shortcuts import redirect, render
8 from django.views.generic import View
9 from django_tables2 import RequestConfig
10 from packaging import version
11 
12 from extras.dashboard.utils import get_dashboard
13 from netbox.forms import SearchForm
14 from netbox.search import LookupTypes
15 from netbox.search.backends import search_backend
16 from netbox.tables import SearchTable
17 from utilities.htmx import is_htmx
18 from utilities.paginator import EnhancedPaginator, get_paginate_count
19 
20 __all__ = (
21     'HomeView',
22     'SearchView',
23 )
24 
25 Link = namedtuple('Link', ('label', 'viewname', 'permission', 'count'))
26 
27 
28 class HomeView(View):
29     template_name = 'home.html'
30 
31     def get(self, request):
32         if settings.LOGIN_REQUIRED and not request.user.is_authenticated:
33             return redirect('login')
34 
35         # Construct the user's custom dashboard layout
36         dashboard = get_dashboard(request.user).get_layout()
37 
38         # Check whether a new release is available. (Only for staff/superusers.)
39         new_release = None
40         if request.user.is_staff or request.user.is_superuser:
41             latest_release = cache.get('latest_release')
42             if latest_release:
43                 release_version, release_url = latest_release
44                 if release_version > version.parse(settings.VERSION):
45                     new_release = {
46                         'version': str(release_version),
47                         'url': release_url,
48                     }
49 
50         return render(request, self.template_name, {
51             'dashboard': dashboard,
52             'new_release': new_release,
53         })
54 
55 
56 class SearchView(View):
57 
58     def get(self, request):
59         results = []
60         highlight = None
61 
62         # Initialize search form
63         form = SearchForm(request.GET) if 'q' in request.GET else SearchForm()
64 
65         if form.is_valid():
66 
67             # Restrict results by object type
68             object_types = []
69             for obj_type in form.cleaned_data['obj_types']:
70                 app_label, model_name = obj_type.split('.')
71                 object_types.append(ContentType.objects.get_by_natural_key(app_label, model_name))
72 
73             lookup = form.cleaned_data['lookup'] or LookupTypes.PARTIAL
74             results = search_backend.search(
75                 form.cleaned_data['q'],
76                 user=request.user,
77                 object_types=object_types,
78                 lookup=lookup
79             )
80 
81             # If performing a regex search, pass the highlight value as a compiled pattern
82             if form.cleaned_data['lookup'] == LookupTypes.REGEX:
83                 try:
84                     highlight = re.compile(f"({form.cleaned_data['q']})", flags=re.IGNORECASE)
85                 except re.error:
86                     pass
87             elif form.cleaned_data['lookup'] != LookupTypes.EXACT:
88                 highlight = form.cleaned_data['q']
89 
90         table = SearchTable(results, highlight=highlight)
91 
92         # Paginate the table results
93         RequestConfig(request, {
94             'paginator_class': EnhancedPaginator,
95             'per_page': get_paginate_count(request)
96         }).configure(table)
97 
98         # If this is an HTMX request, return only the rendered table HTML
99         if is_htmx(request):
100             return render(request, 'htmx/table.html', {
101                 'table': table,
102             })
103 
104         return render(request, 'search.html', {
105             'form': form,
106             'table': table,
107         })
108
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/netbox/extras/dashboard/utils.py b/netbox/extras/dashboard/utils.py
--- a/netbox/extras/dashboard/utils.py
+++ b/netbox/extras/dashboard/utils.py
@@ -53,13 +53,13 @@
     return dashboard
 
 
-def get_default_dashboard():
+def get_default_dashboard(config=None):
     from extras.models import Dashboard
 
     dashboard = Dashboard()
-    default_config = settings.DEFAULT_DASHBOARD or DEFAULT_DASHBOARD
+    config = config or settings.DEFAULT_DASHBOARD or DEFAULT_DASHBOARD
 
-    for widget in default_config:
+    for widget in config:
         id = str(uuid.uuid4())
         dashboard.layout.append({
             'id': id,
diff --git a/netbox/netbox/views/misc.py b/netbox/netbox/views/misc.py
--- a/netbox/netbox/views/misc.py
+++ b/netbox/netbox/views/misc.py
@@ -2,14 +2,17 @@
 from collections import namedtuple
 
 from django.conf import settings
+from django.contrib import messages
 from django.contrib.contenttypes.models import ContentType
 from django.core.cache import cache
 from django.shortcuts import redirect, render
+from django.utils.translation import gettext_lazy as _
 from django.views.generic import View
 from django_tables2 import RequestConfig
 from packaging import version
 
-from extras.dashboard.utils import get_dashboard
+from extras.constants import DEFAULT_DASHBOARD
+from extras.dashboard.utils import get_dashboard, get_default_dashboard
 from netbox.forms import SearchForm
 from netbox.search import LookupTypes
 from netbox.search.backends import search_backend
@@ -33,7 +36,13 @@
             return redirect('login')
 
         # Construct the user's custom dashboard layout
-        dashboard = get_dashboard(request.user).get_layout()
+        try:
+            dashboard = get_dashboard(request.user).get_layout()
+        except Exception:
+            messages.error(request, _(
+                "There was an error loading the dashboard configuration. A default dashboard is in use."
+            ))
+            dashboard = get_default_dashboard(config=DEFAULT_DASHBOARD).get_layout()
 
         # Check whether a new release is available. (Only for staff/superusers.)
         new_release = None

{"golden_diff": "diff --git a/netbox/extras/dashboard/utils.py b/netbox/extras/dashboard/utils.py\n--- a/netbox/extras/dashboard/utils.py\n+++ b/netbox/extras/dashboard/utils.py\n@@ -53,13 +53,13 @@\n     return dashboard\n \n \n-def get_default_dashboard():\n+def get_default_dashboard(config=None):\n     from extras.models import Dashboard\n \n     dashboard = Dashboard()\n-    default_config = settings.DEFAULT_DASHBOARD or DEFAULT_DASHBOARD\n+    config = config or settings.DEFAULT_DASHBOARD or DEFAULT_DASHBOARD\n \n-    for widget in default_config:\n+    for widget in config:\n         id = str(uuid.uuid4())\n         dashboard.layout.append({\n             'id': id,\ndiff --git a/netbox/netbox/views/misc.py b/netbox/netbox/views/misc.py\n--- a/netbox/netbox/views/misc.py\n+++ b/netbox/netbox/views/misc.py\n@@ -2,14 +2,17 @@\n from collections import namedtuple\n \n from django.conf import settings\n+from django.contrib import messages\n from django.contrib.contenttypes.models import ContentType\n from django.core.cache import cache\n from django.shortcuts import redirect, render\n+from django.utils.translation import gettext_lazy as _\n from django.views.generic import View\n from django_tables2 import RequestConfig\n from packaging import version\n \n-from extras.dashboard.utils import get_dashboard\n+from extras.constants import DEFAULT_DASHBOARD\n+from extras.dashboard.utils import get_dashboard, get_default_dashboard\n from netbox.forms import SearchForm\n from netbox.search import LookupTypes\n from netbox.search.backends import search_backend\n@@ -33,7 +36,13 @@\n             return redirect('login')\n \n         # Construct the user's custom dashboard layout\n-        dashboard = get_dashboard(request.user).get_layout()\n+        try:\n+            dashboard = get_dashboard(request.user).get_layout()\n+        except Exception:\n+            messages.error(request, _(\n+                \"There was an error loading the dashboard configuration. A default dashboard is in use.\"\n+            ))\n+            dashboard = get_default_dashboard(config=DEFAULT_DASHBOARD).get_layout()\n \n         # Check whether a new release is available. (Only for staff/superusers.)\n         new_release = None\n", "issue": "User Dashboard can become permanently broken when misconfiguring DEFAULT_DASHBOARD\n### Deployment Type\n\nSelf-hosted\n\n### NetBox Version\n\nv3.7.0\n\n### Python Version\n\n3.9\n\n### Steps to Reproduce\n\n1. User johndoe modifies their dashboard over the GUI\r\n2. Administrator changes DEFAULT_DASHBOARD in configuration.py with a broken configuration (Assigned a wrong value in a bookmarks widget)\r\n3. Bookmark widget looks fine without logging in since it won't load any data\r\n4. After johndoe logs in, they reset their dashboard\r\n5. Site crashes with an Field Error Exception since the dashboard is misconfigured\r\n6. johndoe can't reset their dashboard anymore, even after the error in DEFAULT_DASHBOARD is corrected\n\n### Expected Behavior\n\nWhen resetting the dashboard, I would expect it to now always follow the changes of DEFAULT_DASHBOARD.\n\n### Observed Behavior\n\nResetting the dashboard seems to copy the current state of DEFAULT_DASHBOARD. If that state is broken, a user cannot reset it anymore.\r\nOnly the main page with the dashboard crashes.\n", "before_files": [{"content": "import uuid\n\nfrom django.conf import settings\nfrom django.core.exceptions import ObjectDoesNotExist\n\nfrom netbox.registry import registry\nfrom extras.constants import DEFAULT_DASHBOARD\n\n__all__ = (\n    'get_dashboard',\n    'get_default_dashboard',\n    'get_widget_class',\n    'register_widget',\n)\n\n\ndef register_widget(cls):\n    \"\"\"\n    Decorator for registering a DashboardWidget class.\n    \"\"\"\n    app_label = cls.__module__.split('.', maxsplit=1)[0]\n    label = f'{app_label}.{cls.__name__}'\n    registry['widgets'][label] = cls\n\n    return cls\n\n\ndef get_widget_class(name):\n    \"\"\"\n    Return a registered DashboardWidget class identified by its name.\n    \"\"\"\n    try:\n        return registry['widgets'][name]\n    except KeyError:\n        raise ValueError(f\"Unregistered widget class: {name}\")\n\n\ndef get_dashboard(user):\n    \"\"\"\n    Return the Dashboard for a given User if one exists, or generate a default dashboard.\n    \"\"\"\n    if user.is_anonymous:\n        dashboard = get_default_dashboard()\n    else:\n        try:\n            dashboard = user.dashboard\n        except ObjectDoesNotExist:\n            # Create a dashboard for this user\n            dashboard = get_default_dashboard()\n            dashboard.user = user\n            dashboard.save()\n\n    return dashboard\n\n\ndef get_default_dashboard():\n    from extras.models import Dashboard\n\n    dashboard = Dashboard()\n    default_config = settings.DEFAULT_DASHBOARD or DEFAULT_DASHBOARD\n\n    for widget in default_config:\n        id = str(uuid.uuid4())\n        dashboard.layout.append({\n            'id': id,\n            'w': widget['width'],\n            'h': widget['height'],\n            'x': widget.get('x'),\n            'y': widget.get('y'),\n        })\n        dashboard.config[id] = {\n            'class': widget['widget'],\n            'title': widget.get('title'),\n            'color': widget.get('color'),\n            'config': widget.get('config', {}),\n        }\n\n    return dashboard\n", "path": "netbox/extras/dashboard/utils.py"}, {"content": "import re\nfrom collections import namedtuple\n\nfrom django.conf import settings\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.core.cache import cache\nfrom django.shortcuts import redirect, render\nfrom django.views.generic import View\nfrom django_tables2 import RequestConfig\nfrom packaging import version\n\nfrom extras.dashboard.utils import get_dashboard\nfrom netbox.forms import SearchForm\nfrom netbox.search import LookupTypes\nfrom netbox.search.backends import search_backend\nfrom netbox.tables import SearchTable\nfrom utilities.htmx import is_htmx\nfrom utilities.paginator import EnhancedPaginator, get_paginate_count\n\n__all__ = (\n    'HomeView',\n    'SearchView',\n)\n\nLink = namedtuple('Link', ('label', 'viewname', 'permission', 'count'))\n\n\nclass HomeView(View):\n    template_name = 'home.html'\n\n    def get(self, request):\n        if settings.LOGIN_REQUIRED and not request.user.is_authenticated:\n            return redirect('login')\n\n        # Construct the user's custom dashboard layout\n        dashboard = get_dashboard(request.user).get_layout()\n\n        # Check whether a new release is available. (Only for staff/superusers.)\n        new_release = None\n        if request.user.is_staff or request.user.is_superuser:\n            latest_release = cache.get('latest_release')\n            if latest_release:\n                release_version, release_url = latest_release\n                if release_version > version.parse(settings.VERSION):\n                    new_release = {\n                        'version': str(release_version),\n                        'url': release_url,\n                    }\n\n        return render(request, self.template_name, {\n            'dashboard': dashboard,\n            'new_release': new_release,\n        })\n\n\nclass SearchView(View):\n\n    def get(self, request):\n        results = []\n        highlight = None\n\n        # Initialize search form\n        form = SearchForm(request.GET) if 'q' in request.GET else SearchForm()\n\n        if form.is_valid():\n\n            # Restrict results by object type\n            object_types = []\n            for obj_type in form.cleaned_data['obj_types']:\n                app_label, model_name = obj_type.split('.')\n                object_types.append(ContentType.objects.get_by_natural_key(app_label, model_name))\n\n            lookup = form.cleaned_data['lookup'] or LookupTypes.PARTIAL\n            results = search_backend.search(\n                form.cleaned_data['q'],\n                user=request.user,\n                object_types=object_types,\n                lookup=lookup\n            )\n\n            # If performing a regex search, pass the highlight value as a compiled pattern\n            if form.cleaned_data['lookup'] == LookupTypes.REGEX:\n                try:\n                    highlight = re.compile(f\"({form.cleaned_data['q']})\", flags=re.IGNORECASE)\n                except re.error:\n                    pass\n            elif form.cleaned_data['lookup'] != LookupTypes.EXACT:\n                highlight = form.cleaned_data['q']\n\n        table = SearchTable(results, highlight=highlight)\n\n        # Paginate the table results\n        RequestConfig(request, {\n            'paginator_class': EnhancedPaginator,\n            'per_page': get_paginate_count(request)\n        }).configure(table)\n\n        # If this is an HTMX request, return only the rendered table HTML\n        if is_htmx(request):\n            return render(request, 'htmx/table.html', {\n                'table': table,\n            })\n\n        return render(request, 'search.html', {\n            'form': form,\n            'table': table,\n        })\n", "path": "netbox/netbox/views/misc.py"}], "after_files": [{"content": "import uuid\n\nfrom django.conf import settings\nfrom django.core.exceptions import ObjectDoesNotExist\n\nfrom netbox.registry import registry\nfrom extras.constants import DEFAULT_DASHBOARD\n\n__all__ = (\n    'get_dashboard',\n    'get_default_dashboard',\n    'get_widget_class',\n    'register_widget',\n)\n\n\ndef register_widget(cls):\n    \"\"\"\n    Decorator for registering a DashboardWidget class.\n    \"\"\"\n    app_label = cls.__module__.split('.', maxsplit=1)[0]\n    label = f'{app_label}.{cls.__name__}'\n    registry['widgets'][label] = cls\n\n    return cls\n\n\ndef get_widget_class(name):\n    \"\"\"\n    Return a registered DashboardWidget class identified by its name.\n    \"\"\"\n    try:\n        return registry['widgets'][name]\n    except KeyError:\n        raise ValueError(f\"Unregistered widget class: {name}\")\n\n\ndef get_dashboard(user):\n    \"\"\"\n    Return the Dashboard for a given User if one exists, or generate a default dashboard.\n    \"\"\"\n    if user.is_anonymous:\n        dashboard = get_default_dashboard()\n    else:\n        try:\n            dashboard = user.dashboard\n        except ObjectDoesNotExist:\n            # Create a dashboard for this user\n            dashboard = get_default_dashboard()\n            dashboard.user = user\n            dashboard.save()\n\n    return dashboard\n\n\ndef get_default_dashboard(config=None):\n    from extras.models import Dashboard\n\n    dashboard = Dashboard()\n    config = config or settings.DEFAULT_DASHBOARD or DEFAULT_DASHBOARD\n\n    for widget in config:\n        id = str(uuid.uuid4())\n        dashboard.layout.append({\n            'id': id,\n            'w': widget['width'],\n            'h': widget['height'],\n            'x': widget.get('x'),\n            'y': widget.get('y'),\n        })\n        dashboard.config[id] = {\n            'class': widget['widget'],\n            'title': widget.get('title'),\n            'color': widget.get('color'),\n            'config': widget.get('config', {}),\n        }\n\n    return dashboard\n", "path": "netbox/extras/dashboard/utils.py"}, {"content": "import re\nfrom collections import namedtuple\n\nfrom django.conf import settings\nfrom django.contrib import messages\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.core.cache import cache\nfrom django.shortcuts import redirect, render\nfrom django.utils.translation import gettext_lazy as _\nfrom django.views.generic import View\nfrom django_tables2 import RequestConfig\nfrom packaging import version\n\nfrom extras.constants import DEFAULT_DASHBOARD\nfrom extras.dashboard.utils import get_dashboard, get_default_dashboard\nfrom netbox.forms import SearchForm\nfrom netbox.search import LookupTypes\nfrom netbox.search.backends import search_backend\nfrom netbox.tables import SearchTable\nfrom utilities.htmx import is_htmx\nfrom utilities.paginator import EnhancedPaginator, get_paginate_count\n\n__all__ = (\n    'HomeView',\n    'SearchView',\n)\n\nLink = namedtuple('Link', ('label', 'viewname', 'permission', 'count'))\n\n\nclass HomeView(View):\n    template_name = 'home.html'\n\n    def get(self, request):\n        if settings.LOGIN_REQUIRED and not request.user.is_authenticated:\n            return redirect('login')\n\n        # Construct the user's custom dashboard layout\n        try:\n            dashboard = get_dashboard(request.user).get_layout()\n        except Exception:\n            messages.error(request, _(\n                \"There was an error loading the dashboard configuration. A default dashboard is in use.\"\n            ))\n            dashboard = get_default_dashboard(config=DEFAULT_DASHBOARD).get_layout()\n\n        # Check whether a new release is available. (Only for staff/superusers.)\n        new_release = None\n        if request.user.is_staff or request.user.is_superuser:\n            latest_release = cache.get('latest_release')\n            if latest_release:\n                release_version, release_url = latest_release\n                if release_version > version.parse(settings.VERSION):\n                    new_release = {\n                        'version': str(release_version),\n                        'url': release_url,\n                    }\n\n        return render(request, self.template_name, {\n            'dashboard': dashboard,\n            'new_release': new_release,\n        })\n\n\nclass SearchView(View):\n\n    def get(self, request):\n        results = []\n        highlight = None\n\n        # Initialize search form\n        form = SearchForm(request.GET) if 'q' in request.GET else SearchForm()\n\n        if form.is_valid():\n\n            # Restrict results by object type\n            object_types = []\n            for obj_type in form.cleaned_data['obj_types']:\n                app_label, model_name = obj_type.split('.')\n                object_types.append(ContentType.objects.get_by_natural_key(app_label, model_name))\n\n            lookup = form.cleaned_data['lookup'] or LookupTypes.PARTIAL\n            results = search_backend.search(\n                form.cleaned_data['q'],\n                user=request.user,\n                object_types=object_types,\n                lookup=lookup\n            )\n\n            # If performing a regex search, pass the highlight value as a compiled pattern\n            if form.cleaned_data['lookup'] == LookupTypes.REGEX:\n                try:\n                    highlight = re.compile(f\"({form.cleaned_data['q']})\", flags=re.IGNORECASE)\n                except re.error:\n                    pass\n            elif form.cleaned_data['lookup'] != LookupTypes.EXACT:\n                highlight = form.cleaned_data['q']\n\n        table = SearchTable(results, highlight=highlight)\n\n        # Paginate the table results\n        RequestConfig(request, {\n            'paginator_class': EnhancedPaginator,\n            'per_page': get_paginate_count(request)\n        }).configure(table)\n\n        # If this is an HTMX request, return only the rendered table HTML\n        if is_htmx(request):\n            return render(request, 'htmx/table.html', {\n                'table': table,\n            })\n\n        return render(request, 'search.html', {\n            'form': form,\n            'table': table,\n        })\n", "path": "netbox/netbox/views/misc.py"}]}