Repository: wagtail/wagtail

Issue:
Form media are not included in account edition with settings panels
### Issue Summary

I added some fields including a `RichTextField` to a custom `User` model. Then I added a `UserSettingsPanel(BaseSettingsPanel)` in a new tab, registered via `register_account_settings_panel`.

All worked but I was unable to get the Draftail editor.

The bug is very close to #4466. But I am unsure what is the way to properly fix it, due to panels. Moreover it seems that `form` is an undefined value in `wagtail/admin/templates/wagtailadmin/account/account.html`

### Steps to Reproduce

1. Start a new project with `wagtail start myproject`
2. Custom the User model and account forms this way: https://forge.cliss21.org/cliss21/services_pour_tous/commit/4ab71c92b999fd3dc2872d491f952404c2a935f8
3. Go to `/admin/account/`
3. I locally overcame it this way: https://forge.cliss21.org/cliss21/services_pour_tous/commit/669bf290b0b58a6bc532cd17c2523d3b23afe554

I have confirmed that this issue can be reproduced as described on a fresh Wagtail project.

PS: a link to https://docs.wagtail.io/en/stable/reference/hooks.html#register-account-settings-panel could be done from https://docs.wagtail.io/en/stable/advanced_topics/customisation/custom_user_models.html.

### Technical details

```
$ python --version
Python 3.9.2
$ pip show django | grep Version
Version: 3.2.4
$ pip show wagtail | grep Version:
Version: 2.13.2
```


Discussion:

Resolving patch:
diff --git a/wagtail/admin/views/account.py b/wagtail/admin/views/account.py
--- a/wagtail/admin/views/account.py
+++ b/wagtail/admin/views/account.py
@@ -5,6 +5,7 @@
 from django.contrib.auth import update_session_auth_hash
 from django.contrib.auth import views as auth_views
 from django.db import transaction
+from django.forms import Media
 from django.http import Http404
 from django.shortcuts import redirect
 from django.template.loader import render_to_string
@@ -219,8 +220,9 @@ def account(request):
     for tab, tab_panels in panels_by_tab.items():
         tab_panels.sort(key=lambda panel: panel.order)
 
+    panel_forms = [panel.get_form() for panel in panels]
+
     if request.method == 'POST':
-        panel_forms = [panel.get_form() for panel in panels]
 
         if all(form.is_valid() or not form.is_bound for form in panel_forms):
             with transaction.atomic():
@@ -239,6 +241,10 @@ def account(request):
 
             return redirect('wagtailadmin_account')
 
+    media = Media()
+    for form in panel_forms:
+        media += form.media
+
     # Menu items
     menu_items = []
     for fn in hooks.get_hooks('register_account_menu_item'):
@@ -249,6 +255,7 @@ def account(request):
     return TemplateResponse(request, 'wagtailadmin/account/account.html', {
         'panels_by_tab': panels_by_tab,
         'menu_items': menu_items,
+        'media': media,
     })
 
 


Test patch:
diff --git a/wagtail/admin/tests/test_account_management.py b/wagtail/admin/tests/test_account_management.py
--- a/wagtail/admin/tests/test_account_management.py
+++ b/wagtail/admin/tests/test_account_management.py
@@ -243,6 +243,9 @@ def test_account_view(self):
         else:
             self.assertNotContains(response, "Current time zone:")
 
+        # Form media should be included on the page
+        self.assertContains(response, 'vendor/colorpicker.js')
+
     def test_change_name_post(self):
         response = self.post_form({
             'name_email-first_name': 'Fox',
diff --git a/wagtail/tests/testapp/forms.py b/wagtail/tests/testapp/forms.py
--- a/wagtail/tests/testapp/forms.py
+++ b/wagtail/tests/testapp/forms.py
@@ -1,4 +1,5 @@
 from django import forms
+from django.contrib.auth import get_user_model
 
 from wagtail.admin.forms import WagtailAdminPageForm
 from wagtail.admin.widgets import AdminDateInput
@@ -35,3 +36,14 @@ class AdminStarDateInput(AdminDateInput):
     # the media of the parent class
     class Media:
         js = ['vendor/star_date.js']
+
+
+class FavouriteColourForm(forms.ModelForm):
+    # for testing that form media from account settings panels gets included
+    # on the form page
+    class Meta:
+        model = get_user_model()
+        fields = []
+
+    class Media:
+        js = ['vendor/colorpicker.js']
diff --git a/wagtail/tests/testapp/wagtail_hooks.py b/wagtail/tests/testapp/wagtail_hooks.py
--- a/wagtail/tests/testapp/wagtail_hooks.py
+++ b/wagtail/tests/testapp/wagtail_hooks.py
@@ -9,9 +9,12 @@
 from wagtail.admin.rich_text import HalloPlugin
 from wagtail.admin.rich_text.converters.html_to_contentstate import BlockElementHandler
 from wagtail.admin.search import SearchArea
+from wagtail.admin.views.account import BaseSettingsPanel
 from wagtail.admin.widgets import Button
 from wagtail.core import hooks
 
+from .forms import FavouriteColourForm
+
 
 # Register one hook using decorators...
 @hooks.register('insert_editor_css')
@@ -177,3 +180,12 @@ def register_snippet_listing_button_item(buttons, snippet, user, context=None):
         priority=10,
     )
     buttons.append(item)
+
+
+@hooks.register('register_account_settings_panel')
+class FavouriteColourPanel(BaseSettingsPanel):
+    name = 'favourite_colour'
+    title = "Favourite colour"
+    order = 500
+    form_class = FavouriteColourForm
+    form_object = 'user'