We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`MultipleObjectsReturned` in page children API endpoint
### Describe the Bug
<!-- A clear and concise description of what the bug is. -->
When the children of a page with more than one version with the same slug are requested via the `url` parameter, the error `MultipleObjectsReturned` gets thrown.

### Steps to Reproduce

1. Go to the region Augsbug
2. Create at least one additional version of the Willkommen page with the same slug
3. Open http://localhost:8000/api/augsburg/de/children?url=willkommen
4. See error

### Expected Behavior
<!-- A clear and concise description of what you expected to happen. -->
The children of the page should be returned

### Actual Behavior
<!-- A clear and concise description of what actually happened. -->
The following error appears:
```
Traceback (most recent call last):
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/integreat_cms/api/decorators.py", line 112, in wrap
    return function(request, *args, **kwargs)
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/integreat_cms/api/v3/pages.py", line 184, in children
    root_pages = [get_single_page(request, language_slug)]
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/integreat_cms/api/v3/pages.py", line 116, in get_single_page
    page = get_object_or_404(
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/shortcuts.py", line 76, in get_object_or_404
    return queryset.get(*args, **kwargs)
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/cacheops/query.py", line 351, in get
    return qs._no_monkey.get(qs, *args, **kwargs)
  File "/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/db/models/query.py", line 439, in get
    raise self.model.MultipleObjectsReturned(
integreat_cms.cms.models.pages.page.Page.MultipleObjectsReturned: get() returned more than one Page -- it returned more than 20!
```

### Additional Information
<!-- Add any other context (e.g. logs, screenshots, etc.) about the problem here. -->

The problem is that the `get_object_or_404()` doesn't work with reverse foreign keys, because the same element might be in the queryset multiple times, so this is the culprit:
https://github.com/digitalfabrik/integreat-cms/blob/810bd2f3be861db0148a5e0410b5878ee59bfa17/integreat_cms/api/v3/pages.py#L116-L120
We probably need to add a `distinct()` here and throw an `Http404` manually without the shortcut method.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `integreat_cms/api/v3/pages.py`
Content:
```
1 """
2 pages API endpoint
3 """
4 from django.conf import settings
5 from django.http import JsonResponse, Http404
6 from django.shortcuts import get_object_or_404
7 
8 from ...cms.models import Region, Page
9 from ..decorators import json_response
10 
11 
12 def transform_page(page_translation):
13     """
14     Function to create a dict from a single page_translation Object.
15 
16     :param page_translation: single page translation object
17     :type page_translation: ~integreat_cms.cms.models.pages.page_translation.PageTranslation
18 
19     :return: data necessary for API
20     :rtype: dict
21     """
22     if page_translation.page.icon:
23         thumbnail = settings.BASE_URL + page_translation.page.icon.url
24     else:
25         thumbnail = None
26     if page_translation.page.parent:
27         parent = {
28             "id": page_translation.page.parent.id,
29             "url": page_translation.page.parent.get_translation(
30                 page_translation.language.slug
31             ).backend_base_link,
32             "path": "/"
33             + page_translation.page.parent.get_translation(
34                 page_translation.language.slug
35             ).permalink
36             + "/",
37         }
38     else:
39         parent = {
40             "id": 0,
41             "url": None,
42             "path": None,
43         }
44     return {
45         "id": page_translation.id,
46         "url": page_translation.backend_base_link,
47         "path": "/" + page_translation.permalink + "/",
48         "title": page_translation.title,
49         "modified_gmt": page_translation.combined_last_updated,
50         "excerpt": page_translation.text,
51         "content": page_translation.combined_text,
52         "parent": parent,
53         "order": page_translation.page.lft,  # use left edge indicator of mptt model for order
54         "available_languages": page_translation.available_languages,
55         "thumbnail": thumbnail,
56         "hash": None,
57     }
58 
59 
60 @json_response
61 # pylint: disable=unused-argument
62 def pages(request, region_slug, language_slug):
63     """
64     Function to iterate through all non-archived pages of a region and return them as JSON.
65 
66     :param request: Django request
67     :type request: ~django.http.HttpRequest
68     :param region_slug: slug of a region
69     :type region_slug: str
70     :param language_slug: language slug
71     :type language_slug: str
72 
73     :return: JSON object according to APIv3 pages endpoint definition
74     :rtype: ~django.http.JsonResponse
75     """
76     region = Region.get_current_region(request)
77     result = []
78     for page in region.get_pages():
79         page_translation = page.get_public_translation(language_slug)
80         if page_translation:
81             result.append(transform_page(page_translation))
82     return JsonResponse(
83         result, safe=False
84     )  # Turn off Safe-Mode to allow serializing arrays
85 
86 
87 def get_single_page(request, language_slug):
88     """
89     Helper function returning the desired page or a 404 if the
90     requested page does not exist.
91 
92     :param request: The request that has been sent to the Django server
93     :type request: ~django.http.HttpRequest
94 
95     :param language_slug: Code to identify the desired language
96     :type language_slug: str
97 
98     :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.
99 
100     :raises RuntimeError: If neither the id nor the url parameter is given
101 
102     :return: the requested page
103     :rtype: ~integreat_cms.cms.models.pages.page.Page
104     """
105     region = Region.get_current_region(request)
106 
107     if request.GET.get("id"):
108         page = get_object_or_404(region.pages, id=request.GET.get("id"))
109 
110     elif request.GET.get("url"):
111         # Strip leading and trailing slashes to avoid ambiguous urls
112         url = request.GET.get("url").strip("/")
113         # The last path component of the url is the page translation slug
114         page_translation_slug = url.split("/")[-1]
115         # Get page by filtering for translation slug and translation language slug
116         page = get_object_or_404(
117             region.pages,
118             translations__slug=page_translation_slug,
119             translations__language__slug=language_slug,
120         )
121 
122     else:
123         raise RuntimeError("Either the id or the url parameter is required.")
124 
125     return page
126 
127 
128 @json_response
129 # pylint: disable=unused-argument
130 def single_page(request, region_slug, language_slug):
131     """
132     View function returning the desired page as a JSON or a 404 if the
133     requested page does not exist.
134 
135     :param request: The request that has been sent to the Django server
136     :type request: ~django.http.HttpRequest
137 
138     :param region_slug: Slug defining the region
139     :type region_slug: str
140 
141     :param language_slug: Code to identify the desired language
142     :type language_slug: str
143 
144     :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.
145 
146     :return: JSON with the requested page and a HTTP status 200.
147     :rtype: ~django.http.JsonResponse
148     """
149     try:
150         page = get_single_page(request, language_slug)
151     except RuntimeError as e:
152         return JsonResponse({"error": str(e)}, status=400)
153     # Get most recent public revision of the page
154     page_translation = page.get_public_translation(language_slug)
155     if page_translation:
156         return JsonResponse(transform_page(page_translation), safe=False)
157 
158     raise Http404("No Page matches the given url or id.")
159 
160 
161 @json_response
162 # pylint: disable=unused-argument
163 def children(request, region_slug, language_slug):
164     """
165     Retrieves all children for a single page
166 
167     :param request: The request that has been sent to the Django server
168     :type request: ~django.http.HttpRequest
169 
170     :param region_slug: Slug defining the region
171     :type region_slug: str
172 
173     :param language_slug: Code to identify the desired language
174     :type language_slug: str
175 
176     :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.
177 
178     :return: JSON with the requested page descendants
179     :rtype: ~django.http.JsonResponse
180     """
181     depth = int(request.GET.get("depth", 1))
182     try:
183         # try to get a single ancestor page based on the requests query string
184         root_pages = [get_single_page(request, language_slug)]
185     except RuntimeError:
186         # if neither id nor url is set then get all root pages
187         root_pages = Page.get_root_pages(region_slug)
188         # simulate a virtual root node for WP compatibility
189         # so that depth = 1 returns only those pages without parents (immediate children of this virtual root page)
190         # like in wordpress depth = 0 will return no results in this case
191         depth = depth - 1
192     result = []
193     for root in root_pages:
194         descendants = root.get_descendants_max_depth(True, depth)
195         for descendant in descendants:
196             public_translation = descendant.get_public_translation(language_slug)
197             if public_translation:
198                 result.append(transform_page(public_translation))
199     return JsonResponse(result, safe=False)
200
```
--- 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/integreat_cms/api/v3/pages.py b/integreat_cms/api/v3/pages.py
--- a/integreat_cms/api/v3/pages.py
+++ b/integreat_cms/api/v3/pages.py
@@ -113,11 +113,14 @@
         # The last path component of the url is the page translation slug
         page_translation_slug = url.split("/")[-1]
         # Get page by filtering for translation slug and translation language slug
-        page = get_object_or_404(
-            region.pages,
+        filtered_pages = region.pages.filter(
             translations__slug=page_translation_slug,
             translations__language__slug=language_slug,
-        )
+        ).distinct()
+
+        if len(filtered_pages) != 1:
+            raise Http404("No matching page translation found for url.")
+        page = filtered_pages[0]
 
     else:
         raise RuntimeError("Either the id or the url parameter is required.")

{"golden_diff": "diff --git a/integreat_cms/api/v3/pages.py b/integreat_cms/api/v3/pages.py\n--- a/integreat_cms/api/v3/pages.py\n+++ b/integreat_cms/api/v3/pages.py\n@@ -113,11 +113,14 @@\n         # The last path component of the url is the page translation slug\n         page_translation_slug = url.split(\"/\")[-1]\n         # Get page by filtering for translation slug and translation language slug\n-        page = get_object_or_404(\n-            region.pages,\n+        filtered_pages = region.pages.filter(\n             translations__slug=page_translation_slug,\n             translations__language__slug=language_slug,\n-        )\n+        ).distinct()\n+\n+        if len(filtered_pages) != 1:\n+            raise Http404(\"No matching page translation found for url.\")\n+        page = filtered_pages[0]\n \n     else:\n         raise RuntimeError(\"Either the id or the url parameter is required.\")\n", "issue": "`MultipleObjectsReturned` in page children API endpoint\n### Describe the Bug\r\n<!-- A clear and concise description of what the bug is. -->\r\nWhen the children of a page with more than one version with the same slug are requested via the `url` parameter, the error `MultipleObjectsReturned` gets thrown.\r\n\r\n### Steps to Reproduce\r\n\r\n1. Go to the region Augsbug\r\n2. Create at least one additional version of the Willkommen page with the same slug\r\n3. Open http://localhost:8000/api/augsburg/de/children?url=willkommen\r\n4. See error\r\n\r\n### Expected Behavior\r\n<!-- A clear and concise description of what you expected to happen. -->\r\nThe children of the page should be returned\r\n\r\n### Actual Behavior\r\n<!-- A clear and concise description of what actually happened. -->\r\nThe following error appears:\r\n```\r\nTraceback (most recent call last):\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/core/handlers/exception.py\", line 47, in inner\r\n    response = get_response(request)\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/core/handlers/base.py\", line 181, in _get_response\r\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/integreat_cms/api/decorators.py\", line 112, in wrap\r\n    return function(request, *args, **kwargs)\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/integreat_cms/api/v3/pages.py\", line 184, in children\r\n    root_pages = [get_single_page(request, language_slug)]\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/integreat_cms/api/v3/pages.py\", line 116, in get_single_page\r\n    page = get_object_or_404(\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/shortcuts.py\", line 76, in get_object_or_404\r\n    return queryset.get(*args, **kwargs)\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/db/models/manager.py\", line 85, in manager_method\r\n    return getattr(self.get_queryset(), name)(*args, **kwargs)\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/cacheops/query.py\", line 351, in get\r\n    return qs._no_monkey.get(qs, *args, **kwargs)\r\n  File \"/opt/integreat-cms/.venv/lib/python3.8/site-packages/django/db/models/query.py\", line 439, in get\r\n    raise self.model.MultipleObjectsReturned(\r\nintegreat_cms.cms.models.pages.page.Page.MultipleObjectsReturned: get() returned more than one Page -- it returned more than 20!\r\n```\r\n\r\n### Additional Information\r\n<!-- Add any other context (e.g. logs, screenshots, etc.) about the problem here. -->\r\n\r\nThe problem is that the `get_object_or_404()` doesn't work with reverse foreign keys, because the same element might be in the queryset multiple times, so this is the culprit:\r\nhttps://github.com/digitalfabrik/integreat-cms/blob/810bd2f3be861db0148a5e0410b5878ee59bfa17/integreat_cms/api/v3/pages.py#L116-L120\r\nWe probably need to add a `distinct()` here and throw an `Http404` manually without the shortcut method.\n", "before_files": [{"content": "\"\"\"\npages API endpoint\n\"\"\"\nfrom django.conf import settings\nfrom django.http import JsonResponse, Http404\nfrom django.shortcuts import get_object_or_404\n\nfrom ...cms.models import Region, Page\nfrom ..decorators import json_response\n\n\ndef transform_page(page_translation):\n    \"\"\"\n    Function to create a dict from a single page_translation Object.\n\n    :param page_translation: single page translation object\n    :type page_translation: ~integreat_cms.cms.models.pages.page_translation.PageTranslation\n\n    :return: data necessary for API\n    :rtype: dict\n    \"\"\"\n    if page_translation.page.icon:\n        thumbnail = settings.BASE_URL + page_translation.page.icon.url\n    else:\n        thumbnail = None\n    if page_translation.page.parent:\n        parent = {\n            \"id\": page_translation.page.parent.id,\n            \"url\": page_translation.page.parent.get_translation(\n                page_translation.language.slug\n            ).backend_base_link,\n            \"path\": \"/\"\n            + page_translation.page.parent.get_translation(\n                page_translation.language.slug\n            ).permalink\n            + \"/\",\n        }\n    else:\n        parent = {\n            \"id\": 0,\n            \"url\": None,\n            \"path\": None,\n        }\n    return {\n        \"id\": page_translation.id,\n        \"url\": page_translation.backend_base_link,\n        \"path\": \"/\" + page_translation.permalink + \"/\",\n        \"title\": page_translation.title,\n        \"modified_gmt\": page_translation.combined_last_updated,\n        \"excerpt\": page_translation.text,\n        \"content\": page_translation.combined_text,\n        \"parent\": parent,\n        \"order\": page_translation.page.lft,  # use left edge indicator of mptt model for order\n        \"available_languages\": page_translation.available_languages,\n        \"thumbnail\": thumbnail,\n        \"hash\": None,\n    }\n\n\n@json_response\n# pylint: disable=unused-argument\ndef pages(request, region_slug, language_slug):\n    \"\"\"\n    Function to iterate through all non-archived pages of a region and return them as JSON.\n\n    :param request: Django request\n    :type request: ~django.http.HttpRequest\n    :param region_slug: slug of a region\n    :type region_slug: str\n    :param language_slug: language slug\n    :type language_slug: str\n\n    :return: JSON object according to APIv3 pages endpoint definition\n    :rtype: ~django.http.JsonResponse\n    \"\"\"\n    region = Region.get_current_region(request)\n    result = []\n    for page in region.get_pages():\n        page_translation = page.get_public_translation(language_slug)\n        if page_translation:\n            result.append(transform_page(page_translation))\n    return JsonResponse(\n        result, safe=False\n    )  # Turn off Safe-Mode to allow serializing arrays\n\n\ndef get_single_page(request, language_slug):\n    \"\"\"\n    Helper function returning the desired page or a 404 if the\n    requested page does not exist.\n\n    :param request: The request that has been sent to the Django server\n    :type request: ~django.http.HttpRequest\n\n    :param language_slug: Code to identify the desired language\n    :type language_slug: str\n\n    :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.\n\n    :raises RuntimeError: If neither the id nor the url parameter is given\n\n    :return: the requested page\n    :rtype: ~integreat_cms.cms.models.pages.page.Page\n    \"\"\"\n    region = Region.get_current_region(request)\n\n    if request.GET.get(\"id\"):\n        page = get_object_or_404(region.pages, id=request.GET.get(\"id\"))\n\n    elif request.GET.get(\"url\"):\n        # Strip leading and trailing slashes to avoid ambiguous urls\n        url = request.GET.get(\"url\").strip(\"/\")\n        # The last path component of the url is the page translation slug\n        page_translation_slug = url.split(\"/\")[-1]\n        # Get page by filtering for translation slug and translation language slug\n        page = get_object_or_404(\n            region.pages,\n            translations__slug=page_translation_slug,\n            translations__language__slug=language_slug,\n        )\n\n    else:\n        raise RuntimeError(\"Either the id or the url parameter is required.\")\n\n    return page\n\n\n@json_response\n# pylint: disable=unused-argument\ndef single_page(request, region_slug, language_slug):\n    \"\"\"\n    View function returning the desired page as a JSON or a 404 if the\n    requested page does not exist.\n\n    :param request: The request that has been sent to the Django server\n    :type request: ~django.http.HttpRequest\n\n    :param region_slug: Slug defining the region\n    :type region_slug: str\n\n    :param language_slug: Code to identify the desired language\n    :type language_slug: str\n\n    :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.\n\n    :return: JSON with the requested page and a HTTP status 200.\n    :rtype: ~django.http.JsonResponse\n    \"\"\"\n    try:\n        page = get_single_page(request, language_slug)\n    except RuntimeError as e:\n        return JsonResponse({\"error\": str(e)}, status=400)\n    # Get most recent public revision of the page\n    page_translation = page.get_public_translation(language_slug)\n    if page_translation:\n        return JsonResponse(transform_page(page_translation), safe=False)\n\n    raise Http404(\"No Page matches the given url or id.\")\n\n\n@json_response\n# pylint: disable=unused-argument\ndef children(request, region_slug, language_slug):\n    \"\"\"\n    Retrieves all children for a single page\n\n    :param request: The request that has been sent to the Django server\n    :type request: ~django.http.HttpRequest\n\n    :param region_slug: Slug defining the region\n    :type region_slug: str\n\n    :param language_slug: Code to identify the desired language\n    :type language_slug: str\n\n    :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.\n\n    :return: JSON with the requested page descendants\n    :rtype: ~django.http.JsonResponse\n    \"\"\"\n    depth = int(request.GET.get(\"depth\", 1))\n    try:\n        # try to get a single ancestor page based on the requests query string\n        root_pages = [get_single_page(request, language_slug)]\n    except RuntimeError:\n        # if neither id nor url is set then get all root pages\n        root_pages = Page.get_root_pages(region_slug)\n        # simulate a virtual root node for WP compatibility\n        # so that depth = 1 returns only those pages without parents (immediate children of this virtual root page)\n        # like in wordpress depth = 0 will return no results in this case\n        depth = depth - 1\n    result = []\n    for root in root_pages:\n        descendants = root.get_descendants_max_depth(True, depth)\n        for descendant in descendants:\n            public_translation = descendant.get_public_translation(language_slug)\n            if public_translation:\n                result.append(transform_page(public_translation))\n    return JsonResponse(result, safe=False)\n", "path": "integreat_cms/api/v3/pages.py"}], "after_files": [{"content": "\"\"\"\npages API endpoint\n\"\"\"\nfrom django.conf import settings\nfrom django.http import JsonResponse, Http404\nfrom django.shortcuts import get_object_or_404\n\nfrom ...cms.models import Region, Page\nfrom ..decorators import json_response\n\n\ndef transform_page(page_translation):\n    \"\"\"\n    Function to create a dict from a single page_translation Object.\n\n    :param page_translation: single page translation object\n    :type page_translation: ~integreat_cms.cms.models.pages.page_translation.PageTranslation\n\n    :return: data necessary for API\n    :rtype: dict\n    \"\"\"\n    if page_translation.page.icon:\n        thumbnail = settings.BASE_URL + page_translation.page.icon.url\n    else:\n        thumbnail = None\n    if page_translation.page.parent:\n        parent = {\n            \"id\": page_translation.page.parent.id,\n            \"url\": page_translation.page.parent.get_translation(\n                page_translation.language.slug\n            ).backend_base_link,\n            \"path\": \"/\"\n            + page_translation.page.parent.get_translation(\n                page_translation.language.slug\n            ).permalink\n            + \"/\",\n        }\n    else:\n        parent = {\n            \"id\": 0,\n            \"url\": None,\n            \"path\": None,\n        }\n    return {\n        \"id\": page_translation.id,\n        \"url\": page_translation.backend_base_link,\n        \"path\": \"/\" + page_translation.permalink + \"/\",\n        \"title\": page_translation.title,\n        \"modified_gmt\": page_translation.combined_last_updated,\n        \"excerpt\": page_translation.text,\n        \"content\": page_translation.combined_text,\n        \"parent\": parent,\n        \"order\": page_translation.page.lft,  # use left edge indicator of mptt model for order\n        \"available_languages\": page_translation.available_languages,\n        \"thumbnail\": thumbnail,\n        \"hash\": None,\n    }\n\n\n@json_response\n# pylint: disable=unused-argument\ndef pages(request, region_slug, language_slug):\n    \"\"\"\n    Function to iterate through all non-archived pages of a region and return them as JSON.\n\n    :param request: Django request\n    :type request: ~django.http.HttpRequest\n    :param region_slug: slug of a region\n    :type region_slug: str\n    :param language_slug: language slug\n    :type language_slug: str\n\n    :return: JSON object according to APIv3 pages endpoint definition\n    :rtype: ~django.http.JsonResponse\n    \"\"\"\n    region = Region.get_current_region(request)\n    result = []\n    for page in region.get_pages():\n        page_translation = page.get_public_translation(language_slug)\n        if page_translation:\n            result.append(transform_page(page_translation))\n    return JsonResponse(\n        result, safe=False\n    )  # Turn off Safe-Mode to allow serializing arrays\n\n\ndef get_single_page(request, language_slug):\n    \"\"\"\n    Helper function returning the desired page or a 404 if the\n    requested page does not exist.\n\n    :param request: The request that has been sent to the Django server\n    :type request: ~django.http.HttpRequest\n\n    :param language_slug: Code to identify the desired language\n    :type language_slug: str\n\n    :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.\n\n    :raises RuntimeError: If neither the id nor the url parameter is given\n\n    :return: the requested page\n    :rtype: ~integreat_cms.cms.models.pages.page.Page\n    \"\"\"\n    region = Region.get_current_region(request)\n\n    if request.GET.get(\"id\"):\n        page = get_object_or_404(region.pages, id=request.GET.get(\"id\"))\n\n    elif request.GET.get(\"url\"):\n        # Strip leading and trailing slashes to avoid ambiguous urls\n        url = request.GET.get(\"url\").strip(\"/\")\n        # The last path component of the url is the page translation slug\n        page_translation_slug = url.split(\"/\")[-1]\n        # Get page by filtering for translation slug and translation language slug\n        filtered_pages = region.pages.filter(\n            translations__slug=page_translation_slug,\n            translations__language__slug=language_slug,\n        ).distinct()\n\n        if len(filtered_pages) != 1:\n            raise Http404(\"No matching page translation found for url.\")\n        page = filtered_pages[0]\n\n    else:\n        raise RuntimeError(\"Either the id or the url parameter is required.\")\n\n    return page\n\n\n@json_response\n# pylint: disable=unused-argument\ndef single_page(request, region_slug, language_slug):\n    \"\"\"\n    View function returning the desired page as a JSON or a 404 if the\n    requested page does not exist.\n\n    :param request: The request that has been sent to the Django server\n    :type request: ~django.http.HttpRequest\n\n    :param region_slug: Slug defining the region\n    :type region_slug: str\n\n    :param language_slug: Code to identify the desired language\n    :type language_slug: str\n\n    :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.\n\n    :return: JSON with the requested page and a HTTP status 200.\n    :rtype: ~django.http.JsonResponse\n    \"\"\"\n    try:\n        page = get_single_page(request, language_slug)\n    except RuntimeError as e:\n        return JsonResponse({\"error\": str(e)}, status=400)\n    # Get most recent public revision of the page\n    page_translation = page.get_public_translation(language_slug)\n    if page_translation:\n        return JsonResponse(transform_page(page_translation), safe=False)\n\n    raise Http404(\"No Page matches the given url or id.\")\n\n\n@json_response\n# pylint: disable=unused-argument\ndef children(request, region_slug, language_slug):\n    \"\"\"\n    Retrieves all children for a single page\n\n    :param request: The request that has been sent to the Django server\n    :type request: ~django.http.HttpRequest\n\n    :param region_slug: Slug defining the region\n    :type region_slug: str\n\n    :param language_slug: Code to identify the desired language\n    :type language_slug: str\n\n    :raises ~django.http.Http404: HTTP status 404 if the request is malformed or no page with the given id or url exists.\n\n    :return: JSON with the requested page descendants\n    :rtype: ~django.http.JsonResponse\n    \"\"\"\n    depth = int(request.GET.get(\"depth\", 1))\n    try:\n        # try to get a single ancestor page based on the requests query string\n        root_pages = [get_single_page(request, language_slug)]\n    except RuntimeError:\n        # if neither id nor url is set then get all root pages\n        root_pages = Page.get_root_pages(region_slug)\n        # simulate a virtual root node for WP compatibility\n        # so that depth = 1 returns only those pages without parents (immediate children of this virtual root page)\n        # like in wordpress depth = 0 will return no results in this case\n        depth = depth - 1\n    result = []\n    for root in root_pages:\n        descendants = root.get_descendants_max_depth(True, depth)\n        for descendant in descendants:\n            public_translation = descendant.get_public_translation(language_slug)\n            if public_translation:\n                result.append(transform_page(public_translation))\n    return JsonResponse(result, safe=False)\n", "path": "integreat_cms/api/v3/pages.py"}]}