Skip to content

Commit 9818fd7

Browse files
committed
implemented an asyncified flatpages app
1 parent 9b41e92 commit 9818fd7

File tree

7 files changed

+157
-0
lines changed

7 files changed

+157
-0
lines changed

django_async_extensions/acontrib/flatpages/__init__.py

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from django.contrib import admin
2+
from django.contrib.flatpages.models import FlatPage
3+
from django.utils.translation import gettext_lazy as _
4+
5+
from django_async_extensions.acontrib.flatpages.forms import AsyncFlatPageForm
6+
7+
8+
@admin.register(FlatPage)
9+
class FlatPageAdmin(admin.ModelAdmin):
10+
form = AsyncFlatPageForm
11+
fieldsets = (
12+
(None, {"fields": ("url", "title", "content", "sites")}),
13+
(
14+
_("Advanced options"),
15+
{
16+
"classes": ("collapse",),
17+
"fields": ("registration_required", "template_name"),
18+
},
19+
),
20+
)
21+
list_display = ("url", "title")
22+
list_filter = ("sites", "registration_required")
23+
search_fields = ("url", "title")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from django.apps import AppConfig
2+
from django.utils.translation import gettext_lazy as _
3+
4+
5+
class FlatPagesConfig(AppConfig):
6+
default_auto_field = "django.db.models.AutoField"
7+
name = "django.contrib.flatpages"
8+
verbose_name = _("Flat Pages")
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.contrib.flatpages.forms import FlatpageForm
2+
3+
from asgiref.sync import sync_to_async
4+
5+
6+
class AsyncFlatPageForm(FlatpageForm):
7+
async def asave(self, commit=True):
8+
return await sync_to_async(self.save)(commit=commit)
9+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from django.conf import settings
2+
from django.http import Http404
3+
from django.utils.deprecation import MiddlewareMixin
4+
5+
from asgiref.sync import sync_to_async
6+
7+
from django_async_extensions.acontrib.flatpages.views import flatpage
8+
9+
10+
class AsyncFlatpageFallbackMiddleware(MiddlewareMixin):
11+
async def process_response(self, request, response):
12+
if response.status_code != 404:
13+
return response # No need to check for a flatpage for non-404 responses.
14+
try:
15+
return await flatpage(request, request.path_info)
16+
# Return the original response if any errors happened. Because this
17+
# is a middleware, we can't assume the errors will be caught elsewhere.
18+
except Http404:
19+
return response
20+
except Exception:
21+
if settings.DEBUG:
22+
raise
23+
return response
24+
25+
async def __acall__(self, request):
26+
"""
27+
Async version of __call__ that is swapped in when an async request
28+
is running.
29+
"""
30+
response = None
31+
if hasattr(self, "process_request"):
32+
response = await sync_to_async(
33+
self.process_request,
34+
thread_sensitive=True,
35+
)(request)
36+
response = response or await self.get_response(request)
37+
if hasattr(self, "process_response"):
38+
response = await self.process_response(request, response)
39+
return response
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.urls import path
2+
3+
from django_async_extensions.acontrib.flatpages import views
4+
5+
urlpatterns = [
6+
path("<path:url>", views.flatpage, name="django.contrib.flatpages.views.flatpage"),
7+
]
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from django.conf import settings
2+
from django.contrib.flatpages.models import FlatPage
3+
from django.contrib.sites.shortcuts import get_current_site
4+
from django.http import Http404, HttpResponse, HttpResponsePermanentRedirect
5+
from django.shortcuts import aget_object_or_404
6+
from django.template import loader
7+
from django.utils.safestring import mark_safe
8+
from django.views.decorators.csrf import csrf_protect
9+
10+
DEFAULT_TEMPLATE = "flatpages/default.html"
11+
12+
# This view is called from FlatpageFallbackMiddleware.process_response
13+
# when a 404 is raised, which often means CsrfViewMiddleware.process_view
14+
# has not been called even if CsrfViewMiddleware is installed. So we need
15+
# to use @csrf_protect, in case the template needs {% csrf_token %}.
16+
# However, we can't just wrap this view; if no matching flatpage exists,
17+
# or a redirect is required for authentication, the 404 needs to be returned
18+
# without any CSRF checks. Therefore, we only
19+
# CSRF protect the internal implementation.
20+
21+
22+
async def flatpage(request, url):
23+
"""
24+
Public interface to the flat page view.
25+
26+
Models: `flatpages.flatpages`
27+
Templates: Uses the template defined by the ``template_name`` field,
28+
or :template:`flatpages/default.html` if template_name is not defined.
29+
Context:
30+
flatpage
31+
`flatpages.flatpages` object
32+
"""
33+
if not url.startswith("/"):
34+
url = "/" + url
35+
site_id = get_current_site(request).id
36+
try:
37+
f = await aget_object_or_404(FlatPage, url=url, sites=site_id)
38+
except Http404:
39+
if not url.endswith("/") and settings.APPEND_SLASH:
40+
url += "/"
41+
f = await aget_object_or_404(FlatPage, url=url, sites=site_id)
42+
return HttpResponsePermanentRedirect("%s/" % request.path)
43+
else:
44+
raise
45+
return await render_flatpage(request, f)
46+
47+
48+
@csrf_protect
49+
async def render_flatpage(request, f):
50+
"""
51+
Internal interface to the flat page view.
52+
"""
53+
# If registration is required for accessing this page, and the user isn't
54+
# logged in, redirect to the login page.
55+
user = await request.auser()
56+
if f.registration_required and not user.is_authenticated:
57+
from django.contrib.auth.views import redirect_to_login
58+
59+
return redirect_to_login(request.path)
60+
if f.template_name:
61+
template = loader.select_template((f.template_name, DEFAULT_TEMPLATE))
62+
else:
63+
template = loader.get_template(DEFAULT_TEMPLATE)
64+
65+
# To avoid having to always use the "|safe" filter in flatpage templates,
66+
# mark the title and content as already safe (since they are raw HTML
67+
# content in the first place).
68+
f.title = mark_safe(f.title)
69+
f.content = mark_safe(f.content)
70+
71+
return HttpResponse(template.render({"flatpage": f}, request))

0 commit comments

Comments
 (0)