We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add ability for slugs to be auto incremented on a per model basis
### Is your proposal related to a problem?

I would like to be able to use auto incrementing page slugs in the case of a duplicate slug within the current parent page's URL path.

Example use case: An event calendar where I don't really care so much about the slugs, but there is a high potential for duplicates with the types of events that may be submitted.

The ability to generate 'nice' URLs is a positive selling point of Wagtail that we don't want to undermine but we do want to help users create pages easily.

### Describe the solution you'd like

`Page` models can have an `auto_increment_slug` meta flag, instead of a global Django setting.

When the value is `True`, and pages are created as children of that page (important: the slug behaviour will be determined by parent models, not the page models itself) will have an extra step on form creation.

If a page is being created (not edited) and there is a value error because of a duplicate URL path, instead of failing the form submission it will automatically append an incremented number to the end of the URL. This incrementing number would need to parse the conflicting page path for the last number and then add to it.

**Edge cases to consider**

* What if the path part is not really meant to be an incremental number (E.g. `path/to/blog-post-about-pi-being-3`)
* Confirmation that we want the flag on parent pages and not the page itself that is being created
* Supporting simple numbers only?
* What if the number is `0`, should we increment from `1`
* Should we provide the ability to set the start number `auto_increment_slug = 0` or `auto_increment_slug = 10` or just always assume it is 1 and the first page that contains the slug without any increment will be the zeroth item (without the `-0`)


**Requirements**

* Unit tests are a must
* Documentation for this feature to be added - maybe in https://docs.wagtail.org/en/latest/advanced_topics/customisation/page_editing_interface.html#customising-generated-forms & also page model reference


### Describe alternatives you've considered

* Do not try to solve this in an automated way and keep the page validation as is, users can decide on what the slug should be manually.

### Additional context

* An older PR has an approach (settings) to this problem - see https://github.com/wagtail/wagtail/pull/2454

> This proposed behaviour has come up again independently in #3477. We've now discussed this among the core team - while auto-rewriting of slugs is a behaviour we'd want to avoid in the default case (because the ability to generate 'nice' URLs is a positive selling point of Wagtail that we don't want to undermine...) we're agreed that this would be a worthwhile feature to support on a per-model basis (perhaps with a `auto_increment_slug` meta flag).
> _Originally posted by @gasman in https://github.com/wagtail/wagtail/issues/2454#issuecomment-290208940_ (March 2017)
            

Add ability for slugs to be auto incremented on a per model basis
### Is your proposal related to a problem?

I would like to be able to use auto incrementing page slugs in the case of a duplicate slug within the current parent page's URL path.

Example use case: An event calendar where I don't really care so much about the slugs, but there is a high potential for duplicates with the types of events that may be submitted.

The ability to generate 'nice' URLs is a positive selling point of Wagtail that we don't want to undermine but we do want to help users create pages easily.

### Describe the solution you'd like

`Page` models can have an `auto_increment_slug` meta flag, instead of a global Django setting.

When the value is `True`, and pages are created as children of that page (important: the slug behaviour will be determined by parent models, not the page models itself) will have an extra step on form creation.

If a page is being created (not edited) and there is a value error because of a duplicate URL path, instead of failing the form submission it will automatically append an incremented number to the end of the URL. This incrementing number would need to parse the conflicting page path for the last number and then add to it.

**Edge cases to consider**

* What if the path part is not really meant to be an incremental number (E.g. `path/to/blog-post-about-pi-being-3`)
* Confirmation that we want the flag on parent pages and not the page itself that is being created
* Supporting simple numbers only?
* What if the number is `0`, should we increment from `1`
* Should we provide the ability to set the start number `auto_increment_slug = 0` or `auto_increment_slug = 10` or just always assume it is 1 and the first page that contains the slug without any increment will be the zeroth item (without the `-0`)


**Requirements**

* Unit tests are a must
* Documentation for this feature to be added - maybe in https://docs.wagtail.org/en/latest/advanced_topics/customisation/page_editing_interface.html#customising-generated-forms & also page model reference


### Describe alternatives you've considered

* Do not try to solve this in an automated way and keep the page validation as is, users can decide on what the slug should be manually.

### Additional context

* An older PR has an approach (settings) to this problem - see https://github.com/wagtail/wagtail/pull/2454

> This proposed behaviour has come up again independently in #3477. We've now discussed this among the core team - while auto-rewriting of slugs is a behaviour we'd want to avoid in the default case (because the ability to generate 'nice' URLs is a positive selling point of Wagtail that we don't want to undermine...) we're agreed that this would be a worthwhile feature to support on a per-model basis (perhaps with a `auto_increment_slug` meta flag).
> _Originally posted by @gasman in https://github.com/wagtail/wagtail/issues/2454#issuecomment-290208940_ (March 2017)
            


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wagtail/admin/views/pages/copy.py`
Content:
```
1 from django.shortcuts import redirect
2 from django.template.response import TemplateResponse
3 from django.utils.translation import gettext as _
4 
5 from wagtail import hooks
6 from wagtail.actions.copy_page import CopyPageAction
7 from wagtail.actions.create_alias import CreatePageAliasAction
8 from wagtail.admin import messages
9 from wagtail.admin.auth import user_has_any_page_permission, user_passes_test
10 from wagtail.admin.forms.pages import CopyForm
11 from wagtail.admin.utils import get_valid_next_url_from_request
12 from wagtail.models import Page
13 
14 
15 @user_passes_test(user_has_any_page_permission)
16 def copy(request, page_id):
17     page = Page.objects.get(id=page_id)
18 
19     # Parent page defaults to parent of source page
20     parent_page = page.get_parent()
21 
22     # Check if the user has permission to publish subpages on the parent
23     can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()
24 
25     # Create the form
26     form = CopyForm(
27         request.POST or None, user=request.user, page=page, can_publish=can_publish
28     )
29 
30     next_url = get_valid_next_url_from_request(request)
31 
32     for fn in hooks.get_hooks("before_copy_page"):
33         result = fn(request, page)
34         if hasattr(result, "status_code"):
35             return result
36 
37     # Check if user is submitting
38     if request.method == "POST":
39         # Prefill parent_page in case the form is invalid (as prepopulated value for the form field,
40         # because ModelChoiceField seems to not fall back to the user given value)
41         parent_page = Page.objects.get(id=request.POST["new_parent_page"])
42 
43         if form.is_valid():
44             # Receive the parent page (this should never be empty)
45             if form.cleaned_data["new_parent_page"]:
46                 parent_page = form.cleaned_data["new_parent_page"]
47 
48             # Re-check if the user has permission to publish subpages on the new parent
49             can_publish = parent_page.permissions_for_user(
50                 request.user
51             ).can_publish_subpage()
52             keep_live = can_publish and form.cleaned_data.get("publish_copies")
53 
54             # Copy the page
55             # Note that only users who can publish in the new parent page can create an alias.
56             # This is because alias pages must always match their original page's state.
57             if can_publish and form.cleaned_data.get("alias"):
58                 action = CreatePageAliasAction(
59                     page.specific,
60                     recursive=form.cleaned_data.get("copy_subpages"),
61                     parent=parent_page,
62                     update_slug=form.cleaned_data["new_slug"],
63                     user=request.user,
64                 )
65                 new_page = action.execute(skip_permission_checks=True)
66             else:
67                 action = CopyPageAction(
68                     page=page,
69                     recursive=form.cleaned_data.get("copy_subpages"),
70                     to=parent_page,
71                     update_attrs={
72                         "title": form.cleaned_data["new_title"],
73                         "slug": form.cleaned_data["new_slug"],
74                     },
75                     keep_live=keep_live,
76                     user=request.user,
77                 )
78                 new_page = action.execute()
79 
80             # Give a success message back to the user
81             if form.cleaned_data.get("copy_subpages"):
82                 messages.success(
83                     request,
84                     _("Page '%(page_title)s' and %(subpages_count)s subpages copied.")
85                     % {
86                         "page_title": page.specific_deferred.get_admin_display_title(),
87                         "subpages_count": new_page.get_descendants().count(),
88                     },
89                 )
90             else:
91                 messages.success(
92                     request,
93                     _("Page '%(page_title)s' copied.")
94                     % {"page_title": page.specific_deferred.get_admin_display_title()},
95                 )
96 
97             for fn in hooks.get_hooks("after_copy_page"):
98                 result = fn(request, page, new_page)
99                 if hasattr(result, "status_code"):
100                     return result
101 
102             # Redirect to explore of parent page
103             if next_url:
104                 return redirect(next_url)
105             return redirect("wagtailadmin_explore", parent_page.id)
106 
107     return TemplateResponse(
108         request,
109         "wagtailadmin/pages/copy.html",
110         {
111             "page": page,
112             "form": form,
113             "next": next_url,
114         },
115     )
116
```
--- 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/wagtail/admin/views/pages/copy.py b/wagtail/admin/views/pages/copy.py
--- a/wagtail/admin/views/pages/copy.py
+++ b/wagtail/admin/views/pages/copy.py
@@ -22,8 +22,8 @@
     # Check if the user has permission to publish subpages on the parent
     can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()
 
-    # Create the form
-    form = CopyForm(
+    form_class = getattr(page.specific_class, "copy_form_class", CopyForm)
+    form = form_class(
         request.POST or None, user=request.user, page=page, can_publish=can_publish
     )

{"golden_diff": "diff --git a/wagtail/admin/views/pages/copy.py b/wagtail/admin/views/pages/copy.py\n--- a/wagtail/admin/views/pages/copy.py\n+++ b/wagtail/admin/views/pages/copy.py\n@@ -22,8 +22,8 @@\n     # Check if the user has permission to publish subpages on the parent\n     can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()\n \n-    # Create the form\n-    form = CopyForm(\n+    form_class = getattr(page.specific_class, \"copy_form_class\", CopyForm)\n+    form = form_class(\n         request.POST or None, user=request.user, page=page, can_publish=can_publish\n     )\n", "issue": "Add ability for slugs to be auto incremented on a per model basis\n### Is your proposal related to a problem?\r\n\r\nI would like to be able to use auto incrementing page slugs in the case of a duplicate slug within the current parent page's URL path.\r\n\r\nExample use case: An event calendar where I don't really care so much about the slugs, but there is a high potential for duplicates with the types of events that may be submitted.\r\n\r\nThe ability to generate 'nice' URLs is a positive selling point of Wagtail that we don't want to undermine but we do want to help users create pages easily.\r\n\r\n### Describe the solution you'd like\r\n\r\n`Page` models can have an `auto_increment_slug` meta flag, instead of a global Django setting.\r\n\r\nWhen the value is `True`, and pages are created as children of that page (important: the slug behaviour will be determined by parent models, not the page models itself) will have an extra step on form creation.\r\n\r\nIf a page is being created (not edited) and there is a value error because of a duplicate URL path, instead of failing the form submission it will automatically append an incremented number to the end of the URL. This incrementing number would need to parse the conflicting page path for the last number and then add to it.\r\n\r\n**Edge cases to consider**\r\n\r\n* What if the path part is not really meant to be an incremental number (E.g. `path/to/blog-post-about-pi-being-3`)\r\n* Confirmation that we want the flag on parent pages and not the page itself that is being created\r\n* Supporting simple numbers only?\r\n* What if the number is `0`, should we increment from `1`\r\n* Should we provide the ability to set the start number `auto_increment_slug = 0` or `auto_increment_slug = 10` or just always assume it is 1 and the first page that contains the slug without any increment will be the zeroth item (without the `-0`)\r\n\r\n\r\n**Requirements**\r\n\r\n* Unit tests are a must\r\n* Documentation for this feature to be added - maybe in https://docs.wagtail.org/en/latest/advanced_topics/customisation/page_editing_interface.html#customising-generated-forms & also page model reference\r\n\r\n\r\n### Describe alternatives you've considered\r\n\r\n* Do not try to solve this in an automated way and keep the page validation as is, users can decide on what the slug should be manually.\r\n\r\n### Additional context\r\n\r\n* An older PR has an approach (settings) to this problem - see https://github.com/wagtail/wagtail/pull/2454\r\n\r\n> This proposed behaviour has come up again independently in #3477. We've now discussed this among the core team - while auto-rewriting of slugs is a behaviour we'd want to avoid in the default case (because the ability to generate 'nice' URLs is a positive selling point of Wagtail that we don't want to undermine...) we're agreed that this would be a worthwhile feature to support on a per-model basis (perhaps with a `auto_increment_slug` meta flag).\r\n> _Originally posted by @gasman in https://github.com/wagtail/wagtail/issues/2454#issuecomment-290208940_ (March 2017)\r\n            \r\n\nAdd ability for slugs to be auto incremented on a per model basis\n### Is your proposal related to a problem?\r\n\r\nI would like to be able to use auto incrementing page slugs in the case of a duplicate slug within the current parent page's URL path.\r\n\r\nExample use case: An event calendar where I don't really care so much about the slugs, but there is a high potential for duplicates with the types of events that may be submitted.\r\n\r\nThe ability to generate 'nice' URLs is a positive selling point of Wagtail that we don't want to undermine but we do want to help users create pages easily.\r\n\r\n### Describe the solution you'd like\r\n\r\n`Page` models can have an `auto_increment_slug` meta flag, instead of a global Django setting.\r\n\r\nWhen the value is `True`, and pages are created as children of that page (important: the slug behaviour will be determined by parent models, not the page models itself) will have an extra step on form creation.\r\n\r\nIf a page is being created (not edited) and there is a value error because of a duplicate URL path, instead of failing the form submission it will automatically append an incremented number to the end of the URL. This incrementing number would need to parse the conflicting page path for the last number and then add to it.\r\n\r\n**Edge cases to consider**\r\n\r\n* What if the path part is not really meant to be an incremental number (E.g. `path/to/blog-post-about-pi-being-3`)\r\n* Confirmation that we want the flag on parent pages and not the page itself that is being created\r\n* Supporting simple numbers only?\r\n* What if the number is `0`, should we increment from `1`\r\n* Should we provide the ability to set the start number `auto_increment_slug = 0` or `auto_increment_slug = 10` or just always assume it is 1 and the first page that contains the slug without any increment will be the zeroth item (without the `-0`)\r\n\r\n\r\n**Requirements**\r\n\r\n* Unit tests are a must\r\n* Documentation for this feature to be added - maybe in https://docs.wagtail.org/en/latest/advanced_topics/customisation/page_editing_interface.html#customising-generated-forms & also page model reference\r\n\r\n\r\n### Describe alternatives you've considered\r\n\r\n* Do not try to solve this in an automated way and keep the page validation as is, users can decide on what the slug should be manually.\r\n\r\n### Additional context\r\n\r\n* An older PR has an approach (settings) to this problem - see https://github.com/wagtail/wagtail/pull/2454\r\n\r\n> This proposed behaviour has come up again independently in #3477. We've now discussed this among the core team - while auto-rewriting of slugs is a behaviour we'd want to avoid in the default case (because the ability to generate 'nice' URLs is a positive selling point of Wagtail that we don't want to undermine...) we're agreed that this would be a worthwhile feature to support on a per-model basis (perhaps with a `auto_increment_slug` meta flag).\r\n> _Originally posted by @gasman in https://github.com/wagtail/wagtail/issues/2454#issuecomment-290208940_ (March 2017)\r\n            \r\n\n", "before_files": [{"content": "from django.shortcuts import redirect\nfrom django.template.response import TemplateResponse\nfrom django.utils.translation import gettext as _\n\nfrom wagtail import hooks\nfrom wagtail.actions.copy_page import CopyPageAction\nfrom wagtail.actions.create_alias import CreatePageAliasAction\nfrom wagtail.admin import messages\nfrom wagtail.admin.auth import user_has_any_page_permission, user_passes_test\nfrom wagtail.admin.forms.pages import CopyForm\nfrom wagtail.admin.utils import get_valid_next_url_from_request\nfrom wagtail.models import Page\n\n\n@user_passes_test(user_has_any_page_permission)\ndef copy(request, page_id):\n    page = Page.objects.get(id=page_id)\n\n    # Parent page defaults to parent of source page\n    parent_page = page.get_parent()\n\n    # Check if the user has permission to publish subpages on the parent\n    can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()\n\n    # Create the form\n    form = CopyForm(\n        request.POST or None, user=request.user, page=page, can_publish=can_publish\n    )\n\n    next_url = get_valid_next_url_from_request(request)\n\n    for fn in hooks.get_hooks(\"before_copy_page\"):\n        result = fn(request, page)\n        if hasattr(result, \"status_code\"):\n            return result\n\n    # Check if user is submitting\n    if request.method == \"POST\":\n        # Prefill parent_page in case the form is invalid (as prepopulated value for the form field,\n        # because ModelChoiceField seems to not fall back to the user given value)\n        parent_page = Page.objects.get(id=request.POST[\"new_parent_page\"])\n\n        if form.is_valid():\n            # Receive the parent page (this should never be empty)\n            if form.cleaned_data[\"new_parent_page\"]:\n                parent_page = form.cleaned_data[\"new_parent_page\"]\n\n            # Re-check if the user has permission to publish subpages on the new parent\n            can_publish = parent_page.permissions_for_user(\n                request.user\n            ).can_publish_subpage()\n            keep_live = can_publish and form.cleaned_data.get(\"publish_copies\")\n\n            # Copy the page\n            # Note that only users who can publish in the new parent page can create an alias.\n            # This is because alias pages must always match their original page's state.\n            if can_publish and form.cleaned_data.get(\"alias\"):\n                action = CreatePageAliasAction(\n                    page.specific,\n                    recursive=form.cleaned_data.get(\"copy_subpages\"),\n                    parent=parent_page,\n                    update_slug=form.cleaned_data[\"new_slug\"],\n                    user=request.user,\n                )\n                new_page = action.execute(skip_permission_checks=True)\n            else:\n                action = CopyPageAction(\n                    page=page,\n                    recursive=form.cleaned_data.get(\"copy_subpages\"),\n                    to=parent_page,\n                    update_attrs={\n                        \"title\": form.cleaned_data[\"new_title\"],\n                        \"slug\": form.cleaned_data[\"new_slug\"],\n                    },\n                    keep_live=keep_live,\n                    user=request.user,\n                )\n                new_page = action.execute()\n\n            # Give a success message back to the user\n            if form.cleaned_data.get(\"copy_subpages\"):\n                messages.success(\n                    request,\n                    _(\"Page '%(page_title)s' and %(subpages_count)s subpages copied.\")\n                    % {\n                        \"page_title\": page.specific_deferred.get_admin_display_title(),\n                        \"subpages_count\": new_page.get_descendants().count(),\n                    },\n                )\n            else:\n                messages.success(\n                    request,\n                    _(\"Page '%(page_title)s' copied.\")\n                    % {\"page_title\": page.specific_deferred.get_admin_display_title()},\n                )\n\n            for fn in hooks.get_hooks(\"after_copy_page\"):\n                result = fn(request, page, new_page)\n                if hasattr(result, \"status_code\"):\n                    return result\n\n            # Redirect to explore of parent page\n            if next_url:\n                return redirect(next_url)\n            return redirect(\"wagtailadmin_explore\", parent_page.id)\n\n    return TemplateResponse(\n        request,\n        \"wagtailadmin/pages/copy.html\",\n        {\n            \"page\": page,\n            \"form\": form,\n            \"next\": next_url,\n        },\n    )\n", "path": "wagtail/admin/views/pages/copy.py"}], "after_files": [{"content": "from django.shortcuts import redirect\nfrom django.template.response import TemplateResponse\nfrom django.utils.translation import gettext as _\n\nfrom wagtail import hooks\nfrom wagtail.actions.copy_page import CopyPageAction\nfrom wagtail.actions.create_alias import CreatePageAliasAction\nfrom wagtail.admin import messages\nfrom wagtail.admin.auth import user_has_any_page_permission, user_passes_test\nfrom wagtail.admin.forms.pages import CopyForm\nfrom wagtail.admin.utils import get_valid_next_url_from_request\nfrom wagtail.models import Page\n\n\n@user_passes_test(user_has_any_page_permission)\ndef copy(request, page_id):\n    page = Page.objects.get(id=page_id)\n\n    # Parent page defaults to parent of source page\n    parent_page = page.get_parent()\n\n    # Check if the user has permission to publish subpages on the parent\n    can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()\n\n    form_class = getattr(page.specific_class, \"copy_form_class\", CopyForm)\n    form = form_class(\n        request.POST or None, user=request.user, page=page, can_publish=can_publish\n    )\n\n    next_url = get_valid_next_url_from_request(request)\n\n    for fn in hooks.get_hooks(\"before_copy_page\"):\n        result = fn(request, page)\n        if hasattr(result, \"status_code\"):\n            return result\n\n    # Check if user is submitting\n    if request.method == \"POST\":\n        # Prefill parent_page in case the form is invalid (as prepopulated value for the form field,\n        # because ModelChoiceField seems to not fall back to the user given value)\n        parent_page = Page.objects.get(id=request.POST[\"new_parent_page\"])\n\n        if form.is_valid():\n            # Receive the parent page (this should never be empty)\n            if form.cleaned_data[\"new_parent_page\"]:\n                parent_page = form.cleaned_data[\"new_parent_page\"]\n\n            # Re-check if the user has permission to publish subpages on the new parent\n            can_publish = parent_page.permissions_for_user(\n                request.user\n            ).can_publish_subpage()\n            keep_live = can_publish and form.cleaned_data.get(\"publish_copies\")\n\n            # Copy the page\n            # Note that only users who can publish in the new parent page can create an alias.\n            # This is because alias pages must always match their original page's state.\n            if can_publish and form.cleaned_data.get(\"alias\"):\n                action = CreatePageAliasAction(\n                    page.specific,\n                    recursive=form.cleaned_data.get(\"copy_subpages\"),\n                    parent=parent_page,\n                    update_slug=form.cleaned_data[\"new_slug\"],\n                    user=request.user,\n                )\n                new_page = action.execute(skip_permission_checks=True)\n            else:\n                action = CopyPageAction(\n                    page=page,\n                    recursive=form.cleaned_data.get(\"copy_subpages\"),\n                    to=parent_page,\n                    update_attrs={\n                        \"title\": form.cleaned_data[\"new_title\"],\n                        \"slug\": form.cleaned_data[\"new_slug\"],\n                    },\n                    keep_live=keep_live,\n                    user=request.user,\n                )\n                new_page = action.execute()\n\n            # Give a success message back to the user\n            if form.cleaned_data.get(\"copy_subpages\"):\n                messages.success(\n                    request,\n                    _(\"Page '%(page_title)s' and %(subpages_count)s subpages copied.\")\n                    % {\n                        \"page_title\": page.specific_deferred.get_admin_display_title(),\n                        \"subpages_count\": new_page.get_descendants().count(),\n                    },\n                )\n            else:\n                messages.success(\n                    request,\n                    _(\"Page '%(page_title)s' copied.\")\n                    % {\"page_title\": page.specific_deferred.get_admin_display_title()},\n                )\n\n            for fn in hooks.get_hooks(\"after_copy_page\"):\n                result = fn(request, page, new_page)\n                if hasattr(result, \"status_code\"):\n                    return result\n\n            # Redirect to explore of parent page\n            if next_url:\n                return redirect(next_url)\n            return redirect(\"wagtailadmin_explore\", parent_page.id)\n\n    return TemplateResponse(\n        request,\n        \"wagtailadmin/pages/copy.html\",\n        {\n            \"page\": page,\n            \"form\": form,\n            \"next\": next_url,\n        },\n    )\n", "path": "wagtail/admin/views/pages/copy.py"}]}