plain 0.33.0__tar.gz → 0.34.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plain-0.33.0 → plain-0.34.1}/PKG-INFO +2 -2
- {plain-0.33.0 → plain-0.34.1}/plain/README.md +1 -1
- {plain-0.33.0 → plain-0.34.1}/plain/internal/handlers/exception.py +28 -25
- {plain-0.33.0 → plain-0.34.1}/plain/packages/config.py +8 -16
- {plain-0.33.0 → plain-0.34.1}/plain/packages/registry.py +4 -4
- {plain-0.33.0 → plain-0.34.1}/plain/utils/cache.py +27 -1
- {plain-0.33.0 → plain-0.34.1}/plain/views/base.py +2 -1
- {plain-0.33.0 → plain-0.34.1}/plain/views/errors.py +11 -3
- {plain-0.33.0 → plain-0.34.1}/plain/views/templates.py +4 -0
- {plain-0.33.0 → plain-0.34.1}/pyproject.toml +1 -1
- {plain-0.33.0 → plain-0.34.1}/.gitignore +0 -0
- {plain-0.33.0 → plain-0.34.1}/LICENSE +0 -0
- {plain-0.33.0 → plain-0.34.1}/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/__main__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/assets/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/assets/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/assets/compile.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/assets/finders.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/assets/fingerprints.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/assets/urls.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/assets/views.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/cli/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/cli/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/cli/core.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/cli/formatting.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/cli/print.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/cli/registry.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/cli/startup.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/csrf/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/csrf/middleware.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/csrf/views.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/debug.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/exceptions.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/forms/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/forms/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/forms/boundfield.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/forms/exceptions.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/forms/fields.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/forms/forms.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/http/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/http/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/http/cookie.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/http/multipartparser.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/http/request.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/http/response.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/files/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/files/base.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/files/locks.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/files/move.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/files/temp.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/files/uploadedfile.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/files/uploadhandler.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/files/utils.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/handlers/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/handlers/base.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/handlers/wsgi.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/middleware/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/middleware/headers.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/middleware/https.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/internal/middleware/slash.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/json.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/logs/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/logs/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/logs/configure.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/logs/loggers.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/logs/utils.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/packages/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/packages/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/paginator.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/preflight/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/preflight/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/preflight/files.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/preflight/messages.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/preflight/registry.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/preflight/security.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/preflight/urls.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/runtime/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/runtime/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/runtime/global_settings.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/runtime/user_settings.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/signals/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/signals/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/signals/dispatch/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/signals/dispatch/dispatcher.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/signals/dispatch/license.txt +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/signing.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/templates/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/templates/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/templates/core.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/templates/jinja/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/templates/jinja/environments.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/templates/jinja/extensions.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/templates/jinja/filters.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/templates/jinja/globals.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/test/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/test/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/test/client.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/test/encoding.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/test/exceptions.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/urls/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/urls/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/urls/converters.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/urls/exceptions.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/urls/patterns.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/urls/resolvers.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/urls/routers.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/urls/utils.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/connection.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/crypto.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/datastructures.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/dateparse.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/deconstruct.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/decorators.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/duration.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/encoding.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/functional.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/hashable.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/html.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/http.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/inspect.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/ipv6.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/itercompat.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/module_loading.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/regex_helper.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/safestring.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/text.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/timesince.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/timezone.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/utils/tree.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/validators.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/views/README.md +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/views/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/views/csrf.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/views/exceptions.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/views/forms.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/views/objects.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/views/redirect.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/plain/wsgi.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/.bolt/assets_collected/assets.json +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/.gitignore +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/app/.gitignore +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/app/settings.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/app/test/__init__.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/app/test/default_settings.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/app/urls.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/conftest.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/test_cli.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/test_runtime.py +0 -0
- {plain-0.33.0 → plain-0.34.1}/tests/test_wsgi.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: plain
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.34.1
|
4
4
|
Summary: A web framework for building products with Python.
|
5
5
|
Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
|
6
6
|
License-File: LICENSE
|
@@ -40,7 +40,7 @@ The `plain` package includes everything you need to start handling web requests
|
|
40
40
|
|
41
41
|
- [plain.models](/plain-models/README.md) - Define and interact with your database models.
|
42
42
|
- [plain.cache](/plain-cache/README.md) - A database-driven general purpose cache.
|
43
|
-
- [plain.
|
43
|
+
- [plain.email](/plain-email/README.md) - Send emails with SMTP or custom backends.
|
44
44
|
- [plain.sessions](/plain-sessions/README.md) - User sessions and cookies.
|
45
45
|
- [plain.worker](/plain-worker/README.md) - Backgrounb jobs stored in the database.
|
46
46
|
- [plain.api](/plain-api/README.md) - Build APIs with Plain views.
|
@@ -29,7 +29,7 @@ The `plain` package includes everything you need to start handling web requests
|
|
29
29
|
|
30
30
|
- [plain.models](/plain-models/README.md) - Define and interact with your database models.
|
31
31
|
- [plain.cache](/plain-cache/README.md) - A database-driven general purpose cache.
|
32
|
-
- [plain.
|
32
|
+
- [plain.email](/plain-email/README.md) - Send emails with SMTP or custom backends.
|
33
33
|
- [plain.sessions](/plain-sessions/README.md) - User sessions and cookies.
|
34
34
|
- [plain.worker](/plain-worker/README.md) - Backgrounb jobs stored in the database.
|
35
35
|
- [plain.api](/plain-api/README.md) - Build APIs with Plain views.
|
@@ -45,10 +45,14 @@ def convert_exception_to_response(get_response):
|
|
45
45
|
|
46
46
|
def response_for_exception(request, exc):
|
47
47
|
if isinstance(exc, Http404):
|
48
|
-
response = get_exception_response(
|
48
|
+
response = get_exception_response(
|
49
|
+
request=request, status_code=404, exception=None
|
50
|
+
)
|
49
51
|
|
50
52
|
elif isinstance(exc, PermissionDenied):
|
51
|
-
response = get_exception_response(
|
53
|
+
response = get_exception_response(
|
54
|
+
request=request, status_code=403, exception=exc
|
55
|
+
)
|
52
56
|
log_response(
|
53
57
|
"Forbidden (Permission denied): %s",
|
54
58
|
request.path,
|
@@ -58,7 +62,9 @@ def response_for_exception(request, exc):
|
|
58
62
|
)
|
59
63
|
|
60
64
|
elif isinstance(exc, MultiPartParserError):
|
61
|
-
response = get_exception_response(
|
65
|
+
response = get_exception_response(
|
66
|
+
request=request, status_code=400, exception=None
|
67
|
+
)
|
62
68
|
log_response(
|
63
69
|
"Bad request (Unable to parse request body): %s",
|
64
70
|
request.path,
|
@@ -68,7 +74,9 @@ def response_for_exception(request, exc):
|
|
68
74
|
)
|
69
75
|
|
70
76
|
elif isinstance(exc, BadRequest):
|
71
|
-
response = get_exception_response(
|
77
|
+
response = get_exception_response(
|
78
|
+
request=request, status_code=400, exception=exc
|
79
|
+
)
|
72
80
|
log_response(
|
73
81
|
"%s: %s",
|
74
82
|
str(exc),
|
@@ -91,11 +99,15 @@ def response_for_exception(request, exc):
|
|
91
99
|
exc_info=exc,
|
92
100
|
extra={"status_code": 400, "request": request},
|
93
101
|
)
|
94
|
-
response = get_exception_response(
|
102
|
+
response = get_exception_response(
|
103
|
+
request=request, status_code=400, exception=None
|
104
|
+
)
|
95
105
|
|
96
106
|
else:
|
97
107
|
signals.got_request_exception.send(sender=None, request=request)
|
98
|
-
response = get_exception_response(
|
108
|
+
response = get_exception_response(
|
109
|
+
request=request, status_code=500, exception=None
|
110
|
+
)
|
99
111
|
log_response(
|
100
112
|
"%s: %s",
|
101
113
|
response.reason_phrase,
|
@@ -105,34 +117,25 @@ def response_for_exception(request, exc):
|
|
105
117
|
exception=exc,
|
106
118
|
)
|
107
119
|
|
108
|
-
# Force a TemplateResponse to be rendered.
|
109
|
-
if not getattr(response, "is_rendered", True) and callable(
|
110
|
-
getattr(response, "render", None)
|
111
|
-
):
|
112
|
-
response = response.render()
|
113
|
-
|
114
120
|
return response
|
115
121
|
|
116
122
|
|
117
|
-
def get_exception_response(request, status_code):
|
123
|
+
def get_exception_response(*, request, status_code, exception):
|
118
124
|
try:
|
119
|
-
|
125
|
+
view_class = get_error_view(status_code=status_code, exception=exception)
|
126
|
+
return view_class(request)
|
120
127
|
except Exception:
|
121
128
|
signals.got_request_exception.send(sender=None, request=request)
|
122
|
-
return handle_uncaught_exception()
|
123
129
|
|
130
|
+
# In development mode, re-raise the exception to get a full stack trace
|
131
|
+
if settings.DEBUG:
|
132
|
+
raise
|
124
133
|
|
125
|
-
|
126
|
-
|
127
|
-
Processing for any otherwise uncaught exceptions (those that will
|
128
|
-
generate HTTP 500 responses).
|
129
|
-
"""
|
130
|
-
if settings.DEBUG:
|
131
|
-
raise
|
132
|
-
return ResponseServerError()
|
134
|
+
# If we can't load the view, return a 500 response
|
135
|
+
return ResponseServerError()
|
133
136
|
|
134
137
|
|
135
|
-
def get_error_view(status_code):
|
138
|
+
def get_error_view(*, status_code, exception):
|
136
139
|
views_by_status = settings.HTTP_ERROR_VIEWS
|
137
140
|
if status_code in views_by_status:
|
138
141
|
view = views_by_status[status_code]
|
@@ -142,4 +145,4 @@ def get_error_view(status_code):
|
|
142
145
|
return view.as_view()
|
143
146
|
|
144
147
|
# Create a standard view for any other status code
|
145
|
-
return ErrorView.as_view(status_code=status_code)
|
148
|
+
return ErrorView.as_view(status_code=status_code, exception=exception)
|
@@ -10,7 +10,9 @@ CONFIG_MODULE_NAME = "config"
|
|
10
10
|
class PackageConfig:
|
11
11
|
"""Class representing a Plain application and its configuration."""
|
12
12
|
|
13
|
-
|
13
|
+
package_label: str
|
14
|
+
|
15
|
+
def __init__(self, name):
|
14
16
|
# Full Python path to the application e.g. 'plain.admin.admin'.
|
15
17
|
self.name = name
|
16
18
|
|
@@ -18,28 +20,18 @@ class PackageConfig:
|
|
18
20
|
# registry when it registers the PackageConfig instance.
|
19
21
|
self.packages_registry = None
|
20
22
|
|
21
|
-
|
22
|
-
# subclass, hence the test-and-set pattern.
|
23
|
-
if label and hasattr(self, "label"):
|
24
|
-
raise ImproperlyConfigured(
|
25
|
-
"PackageConfig class should not define a class label attribute and an init label"
|
26
|
-
)
|
27
|
-
|
28
|
-
if label:
|
29
|
-
# Set the label explicitly from the init
|
30
|
-
self.label = label
|
31
|
-
elif not hasattr(self, "label"):
|
23
|
+
if not hasattr(self, "package_label"):
|
32
24
|
# Last component of the Python path to the application e.g. 'admin'.
|
33
25
|
# This value must be unique across a Plain project.
|
34
|
-
self.
|
26
|
+
self.package_label = self.name.rpartition(".")[2]
|
35
27
|
|
36
|
-
if not self.
|
28
|
+
if not self.package_label.isidentifier():
|
37
29
|
raise ImproperlyConfigured(
|
38
|
-
f"The app label '{self.
|
30
|
+
f"The app label '{self.package_label}' is not a valid Python identifier."
|
39
31
|
)
|
40
32
|
|
41
33
|
def __repr__(self):
|
42
|
-
return f"<{self.__class__.__name__}: {self.
|
34
|
+
return f"<{self.__class__.__name__}: {self.package_label}>"
|
43
35
|
|
44
36
|
@cached_property
|
45
37
|
def path(self):
|
@@ -146,7 +146,7 @@ class PackagesRegistry:
|
|
146
146
|
message = f"No installed app with label '{package_label}'."
|
147
147
|
for package_config in self.get_package_configs():
|
148
148
|
if package_config.name == package_label:
|
149
|
-
message += f" Did you mean '{package_config.
|
149
|
+
message += f" Did you mean '{package_config.package_label}'?"
|
150
150
|
break
|
151
151
|
raise LookupError(message)
|
152
152
|
|
@@ -179,11 +179,11 @@ class PackagesRegistry:
|
|
179
179
|
class Config(PackageConfig):
|
180
180
|
pass
|
181
181
|
"""
|
182
|
-
if package_config.
|
182
|
+
if package_config.package_label in self.package_configs:
|
183
183
|
raise ImproperlyConfigured(
|
184
|
-
f"Package labels aren't unique, duplicates: {package_config.
|
184
|
+
f"Package labels aren't unique, duplicates: {package_config.package_label}"
|
185
185
|
)
|
186
|
-
self.package_configs[package_config.
|
186
|
+
self.package_configs[package_config.package_label] = package_config
|
187
187
|
package_config.packages = self
|
188
188
|
|
189
189
|
return package_config
|
@@ -15,13 +15,39 @@ An example: i18n middleware would need to distinguish caches by the
|
|
15
15
|
"Accept-language" header.
|
16
16
|
"""
|
17
17
|
|
18
|
+
import time
|
18
19
|
from collections import defaultdict
|
19
20
|
|
20
|
-
from
|
21
|
+
from .http import http_date
|
22
|
+
from .regex_helper import _lazy_re_compile
|
21
23
|
|
22
24
|
cc_delim_re = _lazy_re_compile(r"\s*,\s*")
|
23
25
|
|
24
26
|
|
27
|
+
def patch_response_headers(response, cache_timeout):
|
28
|
+
"""
|
29
|
+
Add HTTP caching headers to the given HttpResponse: Expires and
|
30
|
+
Cache-Control.
|
31
|
+
|
32
|
+
Each header is only added if it isn't already set.
|
33
|
+
"""
|
34
|
+
if cache_timeout < 0:
|
35
|
+
cache_timeout = 0 # Can't have max-age negative
|
36
|
+
if "Expires" not in response.headers:
|
37
|
+
response.headers["Expires"] = http_date(time.time() + cache_timeout)
|
38
|
+
patch_cache_control(response, max_age=cache_timeout)
|
39
|
+
|
40
|
+
|
41
|
+
def add_never_cache_headers(response):
|
42
|
+
"""
|
43
|
+
Add headers to a response to indicate that a page should never be cached.
|
44
|
+
"""
|
45
|
+
patch_response_headers(response, cache_timeout=-1)
|
46
|
+
patch_cache_control(
|
47
|
+
response, no_cache=True, no_store=True, must_revalidate=True, private=True
|
48
|
+
)
|
49
|
+
|
50
|
+
|
25
51
|
def patch_cache_control(response, **kwargs):
|
26
52
|
"""
|
27
53
|
Patch the Cache-Control header by adding all keyword arguments to it.
|
@@ -20,6 +20,7 @@ class View:
|
|
20
20
|
url_kwargs: dict
|
21
21
|
|
22
22
|
# By default, any of these are allowed if a method is defined for it.
|
23
|
+
# To disallow a defined method, remove it from this list.
|
23
24
|
allowed_http_methods = [
|
24
25
|
"get",
|
25
26
|
"post",
|
@@ -84,7 +85,7 @@ class View:
|
|
84
85
|
return result
|
85
86
|
|
86
87
|
if isinstance(result, str):
|
87
|
-
return Response(result)
|
88
|
+
return Response(result, content_type="text/plain")
|
88
89
|
|
89
90
|
if isinstance(result, list):
|
90
91
|
return JsonResponse(result, safe=False)
|
@@ -7,11 +7,19 @@ from .templates import TemplateView
|
|
7
7
|
class ErrorView(TemplateView):
|
8
8
|
status_code: int
|
9
9
|
|
10
|
-
def __init__(self, status_code=None) -> None:
|
10
|
+
def __init__(self, *, status_code=None, exception=None) -> None:
|
11
11
|
# Allow creating an ErrorView with a status code
|
12
12
|
# e.g. ErrorView.as_view(status_code=404)
|
13
|
-
|
14
|
-
|
13
|
+
self.status_code = status_code or self.status_code
|
14
|
+
|
15
|
+
# Allow creating an ErrorView with an exception
|
16
|
+
self.exception = exception
|
17
|
+
|
18
|
+
def get_template_context(self):
|
19
|
+
context = super().get_template_context()
|
20
|
+
context["status_code"] = self.status_code
|
21
|
+
context["exception"] = self.exception
|
22
|
+
return context
|
15
23
|
|
16
24
|
def get_template_names(self) -> list[str]:
|
17
25
|
return [f"{self.status_code}.html", "error.html"]
|
@@ -27,6 +27,10 @@ class TemplateView(View):
|
|
27
27
|
|
28
28
|
template_name: str | None = None
|
29
29
|
|
30
|
+
def __init__(self, template_name=None):
|
31
|
+
# Allow template_name to be passed in as_view()
|
32
|
+
self.template_name = template_name or self.template_name
|
33
|
+
|
30
34
|
def get_template_context(self) -> dict:
|
31
35
|
return {
|
32
36
|
"request": self.request,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|