mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #34343 -- Moved built-in templates to filesystem.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						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 = {} | ||||
|   | ||||
							
								
								
									
										84
									
								
								django/views/templates/csrf_403.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								django/views/templates/csrf_403.html
									
									
									
									
									
										Normal file
									
								
							| @@ -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> | ||||
							
								
								
									
										21
									
								
								django/views/templates/directory_index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								django/views/templates/directory_index.html
									
									
									
									
									
										Normal file
									
								
							| @@ -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> | ||||
							
								
								
									
										102
									
								
								django/views/templates/i18n_catalog.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								django/views/templates/i18n_catalog.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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): | ||||
|     """ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user