mirror of https://github.com/django/django.git
Fixed #34343 -- Moved built-in templates to filesystem.
This commit is contained in:
parent
bae053d497
commit
8eef22dfed
|
@ -1,6 +1,7 @@
|
|||
**/*.min.js
|
||||
**/vendor/**/*.js
|
||||
django/contrib/gis/templates/**/*.js
|
||||
django/views/templates/*.js
|
||||
docs/_build/**/*.js
|
||||
node_modules/**.js
|
||||
tests/**/*.js
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.template import Context, Engine, TemplateDoesNotExist, loader
|
||||
|
@ -12,95 +14,19 @@ from django.utils.version import get_docs_version
|
|||
# tags cannot be used with this inline templates as makemessages would not be
|
||||
# able to discover the strings.
|
||||
|
||||
CSRF_FAILURE_TEMPLATE = """
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<meta name="robots" content="NONE,NOARCHIVE">
|
||||
<title>403 Forbidden</title>
|
||||
<style type="text/css">
|
||||
html * { padding:0; margin:0; }
|
||||
body * { padding:10px 20px; }
|
||||
body * * { padding:0; }
|
||||
body { font:small sans-serif; background:#eee; color:#000; }
|
||||
body>div { border-bottom:1px solid #ddd; }
|
||||
h1 { font-weight:normal; margin-bottom:.4em; }
|
||||
h1 span { font-size:60%; color:#666; font-weight:normal; }
|
||||
#info { background:#f6f6f6; }
|
||||
#info ul { margin: 0.5em 4em; }
|
||||
#info p, #summary p { padding-top:10px; }
|
||||
#summary { background: #ffc; }
|
||||
#explanation { background:#eee; border-bottom: 0px none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="summary">
|
||||
<h1>{{ title }} <span>(403)</span></h1>
|
||||
<p>{{ main }}</p>
|
||||
{% if no_referer %}
|
||||
<p>{{ no_referer1 }}</p>
|
||||
<p>{{ no_referer2 }}</p>
|
||||
<p>{{ no_referer3 }}</p>
|
||||
{% endif %}
|
||||
{% if no_cookie %}
|
||||
<p>{{ no_cookie1 }}</p>
|
||||
<p>{{ no_cookie2 }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if DEBUG %}
|
||||
<div id="info">
|
||||
<h2>Help</h2>
|
||||
{% if reason %}
|
||||
<p>Reason given for failure:</p>
|
||||
<pre>
|
||||
{{ reason }}
|
||||
</pre>
|
||||
{% endif %}
|
||||
|
||||
<p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when
|
||||
<a
|
||||
href="https://docs.djangoproject.com/en/{{ docs_version }}/ref/csrf/">Django’s
|
||||
CSRF mechanism</a> has not been used correctly. For POST forms, you need to
|
||||
ensure:</p>
|
||||
|
||||
<ul>
|
||||
<li>Your browser is accepting cookies.</li>
|
||||
|
||||
<li>The view function passes a <code>request</code> to the template’s <a
|
||||
href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a>
|
||||
method.</li>
|
||||
|
||||
<li>In the template, there is a <code>{% templatetag openblock %} csrf_token
|
||||
{% templatetag closeblock %}</code> template tag inside each POST form that
|
||||
targets an internal URL.</li>
|
||||
|
||||
<li>If you are not using <code>CsrfViewMiddleware</code>, then you must use
|
||||
<code>csrf_protect</code> on any views that use the <code>csrf_token</code>
|
||||
template tag, as well as those that accept the POST data.</li>
|
||||
|
||||
<li>The form has a valid CSRF token. After logging in in another browser
|
||||
tab or hitting the back button after a login, you may need to reload the
|
||||
page with the form, because the token is rotated after a login.</li>
|
||||
</ul>
|
||||
|
||||
<p>You’re seeing the help section of this page because you have <code>DEBUG =
|
||||
True</code> in your Django settings file. Change that to <code>False</code>,
|
||||
and only the initial error message will be displayed. </p>
|
||||
|
||||
<p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div id="explanation">
|
||||
<p><small>{{ more }}</small></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
||||
""" # NOQA
|
||||
CSRF_FAILURE_TEMPLATE_NAME = "403_csrf.html"
|
||||
|
||||
|
||||
def builtin_template_path(name):
|
||||
"""
|
||||
Return a path to a builtin template.
|
||||
|
||||
Avoid calling this function at the module level or in a class-definition
|
||||
because __file__ may not exist, e.g. in frozen environments.
|
||||
"""
|
||||
return Path(__file__).parent / "templates" / name
|
||||
|
||||
|
||||
def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME):
|
||||
"""
|
||||
Default view used when request fails CSRF protection
|
||||
|
@ -151,8 +77,9 @@ def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME):
|
|||
t = loader.get_template(template_name)
|
||||
except TemplateDoesNotExist:
|
||||
if template_name == CSRF_FAILURE_TEMPLATE_NAME:
|
||||
# If the default template doesn't exist, use the string template.
|
||||
t = Engine().from_string(CSRF_FAILURE_TEMPLATE)
|
||||
# If the default template doesn't exist, use the fallback template.
|
||||
with builtin_template_path("csrf_403.html").open(encoding="utf-8") as fh:
|
||||
t = Engine().from_string(fh.read())
|
||||
c = Context(c)
|
||||
else:
|
||||
# Raise if a developer-specified template doesn't exist.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
|
@ -16,6 +17,16 @@ from django.views.generic import View
|
|||
LANGUAGE_QUERY_PARAMETER = "language"
|
||||
|
||||
|
||||
def builtin_template_path(name):
|
||||
"""
|
||||
Return a path to a builtin template.
|
||||
|
||||
Avoid calling this function at the module level or in a class-definition
|
||||
because __file__ may not exist, e.g. in frozen environments.
|
||||
"""
|
||||
return Path(__file__).parent / "templates" / name
|
||||
|
||||
|
||||
def set_language(request):
|
||||
"""
|
||||
Redirect to a given URL while setting the chosen language in the session
|
||||
|
@ -84,112 +95,6 @@ def get_formats():
|
|||
return {attr: get_format(attr) for attr in FORMAT_SETTINGS}
|
||||
|
||||
|
||||
js_catalog_template = r"""
|
||||
{% autoescape off %}
|
||||
'use strict';
|
||||
{
|
||||
const globals = this;
|
||||
const django = globals.django || (globals.django = {});
|
||||
|
||||
{% if plural %}
|
||||
django.pluralidx = function(n) {
|
||||
const v = {{ plural }};
|
||||
if (typeof v === 'boolean') {
|
||||
return v ? 1 : 0;
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
};
|
||||
{% else %}
|
||||
django.pluralidx = function(count) { return (count == 1) ? 0 : 1; };
|
||||
{% endif %}
|
||||
|
||||
/* gettext library */
|
||||
|
||||
django.catalog = django.catalog || {};
|
||||
{% if catalog_str %}
|
||||
const newcatalog = {{ catalog_str }};
|
||||
for (const key in newcatalog) {
|
||||
django.catalog[key] = newcatalog[key];
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
if (!django.jsi18n_initialized) {
|
||||
django.gettext = function(msgid) {
|
||||
const value = django.catalog[msgid];
|
||||
if (typeof value === 'undefined') {
|
||||
return msgid;
|
||||
} else {
|
||||
return (typeof value === 'string') ? value : value[0];
|
||||
}
|
||||
};
|
||||
|
||||
django.ngettext = function(singular, plural, count) {
|
||||
const value = django.catalog[singular];
|
||||
if (typeof value === 'undefined') {
|
||||
return (count == 1) ? singular : plural;
|
||||
} else {
|
||||
return value.constructor === Array ? value[django.pluralidx(count)] : value;
|
||||
}
|
||||
};
|
||||
|
||||
django.gettext_noop = function(msgid) { return msgid; };
|
||||
|
||||
django.pgettext = function(context, msgid) {
|
||||
let value = django.gettext(context + '\x04' + msgid);
|
||||
if (value.includes('\x04')) {
|
||||
value = msgid;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
django.npgettext = function(context, singular, plural, count) {
|
||||
let value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
|
||||
if (value.includes('\x04')) {
|
||||
value = django.ngettext(singular, plural, count);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
django.interpolate = function(fmt, obj, named) {
|
||||
if (named) {
|
||||
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
|
||||
} else {
|
||||
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* formatting library */
|
||||
|
||||
django.formats = {{ formats_str }};
|
||||
|
||||
django.get_format = function(format_type) {
|
||||
const value = django.formats[format_type];
|
||||
if (typeof value === 'undefined') {
|
||||
return format_type;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/* add to global namespace */
|
||||
globals.pluralidx = django.pluralidx;
|
||||
globals.gettext = django.gettext;
|
||||
globals.ngettext = django.ngettext;
|
||||
globals.gettext_noop = django.gettext_noop;
|
||||
globals.pgettext = django.pgettext;
|
||||
globals.npgettext = django.npgettext;
|
||||
globals.interpolate = django.interpolate;
|
||||
globals.get_format = django.get_format;
|
||||
|
||||
django.jsi18n_initialized = true;
|
||||
}
|
||||
};
|
||||
{% endautoescape %}
|
||||
""" # NOQA
|
||||
|
||||
|
||||
class JavaScriptCatalog(View):
|
||||
"""
|
||||
Return the selected language catalog as a JavaScript library.
|
||||
|
@ -308,7 +213,8 @@ class JavaScriptCatalog(View):
|
|||
def indent(s):
|
||||
return s.replace("\n", "\n ")
|
||||
|
||||
template = Engine().from_string(js_catalog_template)
|
||||
with builtin_template_path("i18n_catalog.js").open(encoding="utf-8") as fh:
|
||||
template = Engine().from_string(fh.read())
|
||||
context["catalog_str"] = (
|
||||
indent(json.dumps(context["catalog"], sort_keys=True, indent=2))
|
||||
if context["catalog"]
|
||||
|
|
|
@ -14,6 +14,16 @@ from django.utils.translation import gettext as _
|
|||
from django.utils.translation import gettext_lazy
|
||||
|
||||
|
||||
def builtin_template_path(name):
|
||||
"""
|
||||
Return a path to a builtin template.
|
||||
|
||||
Avoid calling this function at the module level or in a class-definition
|
||||
because __file__ may not exist, e.g. in frozen environments.
|
||||
"""
|
||||
return Path(__file__).parent / "templates" / name
|
||||
|
||||
|
||||
def serve(request, path, document_root=None, show_indexes=False):
|
||||
"""
|
||||
Serve static files below a given point in the directory structure.
|
||||
|
@ -53,29 +63,7 @@ def serve(request, path, document_root=None, show_indexes=False):
|
|||
return response
|
||||
|
||||
|
||||
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
|
||||
{% load i18n %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="robots" content="NONE,NOARCHIVE">
|
||||
<title>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</h1>
|
||||
<ul>
|
||||
{% if directory != "/" %}
|
||||
<li><a href="../">../</a></li>
|
||||
{% endif %}
|
||||
{% for f in file_list %}
|
||||
<li><a href="{{ f|urlencode }}">{{ f }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
# Translatable string for static directory index template title.
|
||||
template_translatable = gettext_lazy("Index of %(directory)s")
|
||||
|
||||
|
||||
|
@ -88,9 +76,10 @@ def directory_index(path, fullpath):
|
|||
]
|
||||
)
|
||||
except TemplateDoesNotExist:
|
||||
t = Engine(libraries={"i18n": "django.templatetags.i18n"}).from_string(
|
||||
DEFAULT_DIRECTORY_INDEX_TEMPLATE
|
||||
)
|
||||
with builtin_template_path("directory_index.html").open(encoding="utf-8") as fh:
|
||||
t = Engine(libraries={"i18n": "django.templatetags.i18n"}).from_string(
|
||||
fh.read()
|
||||
)
|
||||
c = Context()
|
||||
else:
|
||||
c = {}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<meta name="robots" content="NONE,NOARCHIVE">
|
||||
<title>403 Forbidden</title>
|
||||
<style type="text/css">
|
||||
html * { padding:0; margin:0; }
|
||||
body * { padding:10px 20px; }
|
||||
body * * { padding:0; }
|
||||
body { font:small sans-serif; background:#eee; color:#000; }
|
||||
body>div { border-bottom:1px solid #ddd; }
|
||||
h1 { font-weight:normal; margin-bottom:.4em; }
|
||||
h1 span { font-size:60%; color:#666; font-weight:normal; }
|
||||
#info { background:#f6f6f6; }
|
||||
#info ul { margin: 0.5em 4em; }
|
||||
#info p, #summary p { padding-top:10px; }
|
||||
#summary { background: #ffc; }
|
||||
#explanation { background:#eee; border-bottom: 0px none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="summary">
|
||||
<h1>{{ title }} <span>(403)</span></h1>
|
||||
<p>{{ main }}</p>
|
||||
{% if no_referer %}
|
||||
<p>{{ no_referer1 }}</p>
|
||||
<p>{{ no_referer2 }}</p>
|
||||
<p>{{ no_referer3 }}</p>
|
||||
{% endif %}
|
||||
{% if no_cookie %}
|
||||
<p>{{ no_cookie1 }}</p>
|
||||
<p>{{ no_cookie2 }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if DEBUG %}
|
||||
<div id="info">
|
||||
<h2>Help</h2>
|
||||
{% if reason %}
|
||||
<p>Reason given for failure:</p>
|
||||
<pre>
|
||||
{{ reason }}
|
||||
</pre>
|
||||
{% endif %}
|
||||
|
||||
<p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when
|
||||
<a
|
||||
href="https://docs.djangoproject.com/en/{{ docs_version }}/ref/csrf/">Django’s
|
||||
CSRF mechanism</a> has not been used correctly. For POST forms, you need to
|
||||
ensure:</p>
|
||||
|
||||
<ul>
|
||||
<li>Your browser is accepting cookies.</li>
|
||||
|
||||
<li>The view function passes a <code>request</code> to the template’s <a
|
||||
href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a>
|
||||
method.</li>
|
||||
|
||||
<li>In the template, there is a <code>{% templatetag openblock %} csrf_token
|
||||
{% templatetag closeblock %}</code> template tag inside each POST form that
|
||||
targets an internal URL.</li>
|
||||
|
||||
<li>If you are not using <code>CsrfViewMiddleware</code>, then you must use
|
||||
<code>csrf_protect</code> on any views that use the <code>csrf_token</code>
|
||||
template tag, as well as those that accept the POST data.</li>
|
||||
|
||||
<li>The form has a valid CSRF token. After logging in in another browser
|
||||
tab or hitting the back button after a login, you may need to reload the
|
||||
page with the form, because the token is rotated after a login.</li>
|
||||
</ul>
|
||||
|
||||
<p>You’re seeing the help section of this page because you have <code>DEBUG =
|
||||
True</code> in your Django settings file. Change that to <code>False</code>,
|
||||
and only the initial error message will be displayed. </p>
|
||||
|
||||
<p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div id="explanation">
|
||||
<p><small>{{ more }}</small></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
{% load i18n %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="robots" content="NONE,NOARCHIVE">
|
||||
<title>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</h1>
|
||||
<ul>
|
||||
{% if directory != "/" %}
|
||||
<li><a href="../">../</a></li>
|
||||
{% endif %}
|
||||
{% for f in file_list %}
|
||||
<li><a href="{{ f|urlencode }}">{{ f }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,102 @@
|
|||
{% autoescape off %}
|
||||
'use strict';
|
||||
{
|
||||
const globals = this;
|
||||
const django = globals.django || (globals.django = {});
|
||||
|
||||
{% if plural %}
|
||||
django.pluralidx = function(n) {
|
||||
const v = {{ plural }};
|
||||
if (typeof v === 'boolean') {
|
||||
return v ? 1 : 0;
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
};
|
||||
{% else %}
|
||||
django.pluralidx = function(count) { return (count == 1) ? 0 : 1; };
|
||||
{% endif %}
|
||||
|
||||
/* gettext library */
|
||||
|
||||
django.catalog = django.catalog || {};
|
||||
{% if catalog_str %}
|
||||
const newcatalog = {{ catalog_str }};
|
||||
for (const key in newcatalog) {
|
||||
django.catalog[key] = newcatalog[key];
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
if (!django.jsi18n_initialized) {
|
||||
django.gettext = function(msgid) {
|
||||
const value = django.catalog[msgid];
|
||||
if (typeof value === 'undefined') {
|
||||
return msgid;
|
||||
} else {
|
||||
return (typeof value === 'string') ? value : value[0];
|
||||
}
|
||||
};
|
||||
|
||||
django.ngettext = function(singular, plural, count) {
|
||||
const value = django.catalog[singular];
|
||||
if (typeof value === 'undefined') {
|
||||
return (count == 1) ? singular : plural;
|
||||
} else {
|
||||
return value.constructor === Array ? value[django.pluralidx(count)] : value;
|
||||
}
|
||||
};
|
||||
|
||||
django.gettext_noop = function(msgid) { return msgid; };
|
||||
|
||||
django.pgettext = function(context, msgid) {
|
||||
let value = django.gettext(context + '\x04' + msgid);
|
||||
if (value.includes('\x04')) {
|
||||
value = msgid;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
django.npgettext = function(context, singular, plural, count) {
|
||||
let value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
|
||||
if (value.includes('\x04')) {
|
||||
value = django.ngettext(singular, plural, count);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
django.interpolate = function(fmt, obj, named) {
|
||||
if (named) {
|
||||
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
|
||||
} else {
|
||||
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* formatting library */
|
||||
|
||||
django.formats = {{ formats_str }};
|
||||
|
||||
django.get_format = function(format_type) {
|
||||
const value = django.formats[format_type];
|
||||
if (typeof value === 'undefined') {
|
||||
return format_type;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/* add to global namespace */
|
||||
globals.pluralidx = django.pluralidx;
|
||||
globals.gettext = django.gettext;
|
||||
globals.ngettext = django.ngettext;
|
||||
globals.gettext_noop = django.gettext_noop;
|
||||
globals.pgettext = django.pgettext;
|
||||
globals.npgettext = django.npgettext;
|
||||
globals.interpolate = django.interpolate;
|
||||
globals.get_format = django.get_format;
|
||||
|
||||
django.jsi18n_initialized = true;
|
||||
}
|
||||
};
|
||||
{% endautoescape %}
|
|
@ -1,3 +1,5 @@
|
|||
from unittest import mock
|
||||
|
||||
from django.template import TemplateDoesNotExist
|
||||
from django.test import Client, RequestFactory, SimpleTestCase, override_settings
|
||||
from django.utils.translation import override
|
||||
|
@ -117,3 +119,15 @@ class CsrfViewTests(SimpleTestCase):
|
|||
request = factory.post("/")
|
||||
with self.assertRaises(TemplateDoesNotExist):
|
||||
csrf_failure(request, template_name="nonexistent.html")
|
||||
|
||||
def test_template_encoding(self):
|
||||
"""
|
||||
The template is loaded directly, not via a template loader, and should
|
||||
be opened as utf-8 charset as is the default specified on template
|
||||
engines.
|
||||
"""
|
||||
from django.views.csrf import Path
|
||||
|
||||
with mock.patch.object(Path, "open") as m:
|
||||
csrf_failure(mock.MagicMock(), mock.Mock())
|
||||
m.assert_called_once_with(encoding="utf-8")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import gettext
|
||||
import json
|
||||
from os import path
|
||||
from unittest import mock
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import (
|
||||
|
@ -507,6 +508,20 @@ class I18NViewTests(SimpleTestCase):
|
|||
with self.assertRaisesMessage(ValueError, msg):
|
||||
view(request, packages="unknown_package+unknown_package2")
|
||||
|
||||
def test_template_encoding(self):
|
||||
"""
|
||||
The template is loaded directly, not via a template loader, and should
|
||||
be opened as utf-8 charset as is the default specified on template
|
||||
engines.
|
||||
"""
|
||||
from django.views.i18n import Path
|
||||
|
||||
view = JavaScriptCatalog.as_view()
|
||||
request = RequestFactory().get("/")
|
||||
with mock.patch.object(Path, "open") as m:
|
||||
view(request)
|
||||
m.assert_called_once_with(encoding="utf-8")
|
||||
|
||||
|
||||
@override_settings(ROOT_URLCONF="view_tests.urls")
|
||||
class I18nSeleniumTests(SeleniumTestCase):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import mimetypes
|
||||
import unittest
|
||||
from os import path
|
||||
from unittest import mock
|
||||
from urllib.parse import quote
|
||||
|
||||
from django.conf.urls.static import static
|
||||
|
@ -8,7 +9,7 @@ from django.core.exceptions import ImproperlyConfigured
|
|||
from django.http import FileResponse, HttpResponseNotModified
|
||||
from django.test import SimpleTestCase, override_settings
|
||||
from django.utils.http import http_date
|
||||
from django.views.static import was_modified_since
|
||||
from django.views.static import directory_index, was_modified_since
|
||||
|
||||
from .. import urls
|
||||
from ..urls import media_dir
|
||||
|
@ -152,6 +153,18 @@ class StaticTests(SimpleTestCase):
|
|||
response = self.client.get("/%s/" % self.prefix)
|
||||
self.assertEqual(response.content, b"Test index")
|
||||
|
||||
def test_template_encoding(self):
|
||||
"""
|
||||
The template is loaded directly, not via a template loader, and should
|
||||
be opened as utf-8 charset as is the default specified on template
|
||||
engines.
|
||||
"""
|
||||
from django.views.static import Path
|
||||
|
||||
with mock.patch.object(Path, "open") as m:
|
||||
directory_index(mock.MagicMock(), mock.MagicMock())
|
||||
m.assert_called_once_with(encoding="utf-8")
|
||||
|
||||
|
||||
class StaticHelperTest(StaticTests):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue