diff --git a/mezzanine/bin/runtests.py b/mezzanine/bin/runtests.py
index e82ed1a65b..718fd72fed 100755
--- a/mezzanine/bin/runtests.py
+++ b/mezzanine/bin/runtests.py
@@ -45,7 +45,8 @@ def main(package="mezzanine", args=()):
# Require the mezzanine.accounts app. We use settings.INSTALLED_APPS here so
# the syntax test doesn't complain about an undefined name.
if "mezzanine.accounts" not in settings.INSTALLED_APPS:
- INSTALLED_APPS = list(settings.INSTALLED_APPS) + ["mezzanine.accounts"]
+ INSTALLED_APPS = list(settings.INSTALLED_APPS) + ["mezzanine.accounts",
+ "django.contrib.messages"]
# Use the MD5 password hasher by default for quicker test runs.
PASSWORD_HASHERS = ('django.contrib.auth.hashers.MD5PasswordHasher',)
diff --git a/mezzanine/core/admin.py b/mezzanine/core/admin.py
index 9892bd67f5..d7d40a7cdd 100644
--- a/mezzanine/core/admin.py
+++ b/mezzanine/core/admin.py
@@ -301,7 +301,8 @@ def __init__(self, *args, **kwargs):
self.model._meta.many_to_many)
for field in reversed(fields):
if field.name not in exclude_fields and field.editable:
- if not hasattr(field, "translated_field"):
+ if not hasattr(field, "translated_field") and field.name \
+ not in self.fieldsets[0][1]["fields"]:
self.fieldsets[0][1]["fields"].insert(3, field.name)
@property
diff --git a/mezzanine/core/middleware.py b/mezzanine/core/middleware.py
index f2bca64c6c..fca2d044f0 100755
--- a/mezzanine/core/middleware.py
+++ b/mezzanine/core/middleware.py
@@ -172,7 +172,7 @@ def process_response(self, request, response):
context = RequestContext(request)
for i, part in enumerate(parts):
if i % 2:
- part = Template(part).render(context).encode("utf-8")
+ part = Template(part.decode('utf-8')).render(context).encode("utf-8")
parts[i] = part
response.content = b"".join(parts)
response["Content-Length"] = len(response.content)
diff --git a/mezzanine/core/templates/admin/base_site.html b/mezzanine/core/templates/admin/base_site.html
index c282b6a7b2..f277b38150 100644
--- a/mezzanine/core/templates/admin/base_site.html
+++ b/mezzanine/core/templates/admin/base_site.html
@@ -1,5 +1,5 @@
{% extends "admin/base.html" %}
-{% load mezzanine_tags i18n staticfiles %}
+{% load mezzanine_tags i18n staticfiles static %}
{% block title %}{{ title }} | Mezzanine{% endblock %}
@@ -18,7 +18,7 @@
window.__tinymce_css = '{% static "mezzanine/css/tinymce.css" %}';
window.__admin_url = '{{ admin_index_url }}';
window.__static_proxy = '{{ static_proxy_url }}';
- window.__admin_media_prefix__ = '{% static "admin" %}/';
+ window.__admin_media_prefix__ = '{% get_static_prefix %}/admin/';
window.__grappelli_installed = {{ settings.GRAPPELLI_INSTALLED|lower }};
window.__admin_menu_collapsed = {{ settings.ADMIN_MENU_COLLAPSED|lower }};
window.__language_code = '{{ LANGUAGE_CODE }}';
diff --git a/mezzanine/core/templatetags/mezzanine_tags.py b/mezzanine/core/templatetags/mezzanine_tags.py
index 6b0dc882ea..c39806a5bf 100644
--- a/mezzanine/core/templatetags/mezzanine_tags.py
+++ b/mezzanine/core/templatetags/mezzanine_tags.py
@@ -18,8 +18,8 @@
from django.urls import reverse, resolve, NoReverseMatch
from django.db.models import Model
from django.template import Node, Template, TemplateSyntaxError
-from django.template.base import (TOKEN_BLOCK, TOKEN_COMMENT,
- TOKEN_TEXT, TOKEN_VAR, TextNode)
+from django.template.base import TextNode
+
from django.template.defaultfilters import escape
from django.template.loader import get_template
from django.utils import translation
@@ -38,6 +38,20 @@
from mezzanine.utils.views import is_editable
from mezzanine import template
+try:
+ from django.template.base import TokenType
+
+except ImportError:
+ # Django <2.1 uses separate constants for token types
+ from django.template.base import (
+ TOKEN_BLOCK, TOKEN_TEXT, TOKEN_VAR, TOKEN_COMMENT
+ )
+
+ class TokenType:
+ TEXT = TOKEN_TEXT
+ VAR = TOKEN_VAR
+ BLOCK = TOKEN_BLOCK
+ COMMENT = TOKEN_COMMENT
register = template.Library()
@@ -74,16 +88,16 @@ def nevercache(parser, token):
text = []
end_tag = "endnevercache"
tag_mapping = {
- TOKEN_TEXT: ("", ""),
- TOKEN_VAR: ("{{", "}}"),
- TOKEN_BLOCK: ("{%", "%}"),
- TOKEN_COMMENT: ("{#", "#}"),
+ TokenType.TEXT: ("", ""),
+ TokenType.VAR: ("{{", "}}"),
+ TokenType.BLOCK: ("{%", "%}"),
+ TokenType.COMMENT: ("{#", "#}"),
}
delimiter = nevercache_token()
while parser.tokens:
token = parser.next_token()
token_type = token.token_type
- if token_type == TOKEN_BLOCK and token.contents == end_tag:
+ if token_type == TokenType.BLOCK and token.contents == end_tag:
return TextNode(delimiter + "".join(text) + delimiter)
start, end = tag_mapping[token_type]
text.append("%s%s%s" % (start, token.contents, end))
@@ -172,7 +186,7 @@ def ifinstalled(parser, token):
if app.strip("\"'") not in settings.INSTALLED_APPS:
while unmatched_end_tag:
token = parser.tokens.pop(0)
- if token.token_type == TOKEN_BLOCK:
+ if token.token_type == TokenType.BLOCK:
block_name = token.contents.split()[0]
if block_name == tag:
unmatched_end_tag += 1
diff --git a/mezzanine/core/tests.py b/mezzanine/core/tests.py
index e3100cfb4c..ac0c30a95c 100644
--- a/mezzanine/core/tests.py
+++ b/mezzanine/core/tests.py
@@ -301,10 +301,10 @@ def test_static_proxy_with_static_url_with_full_host(self):
self._static_proxy(querystring)
def _get_csrftoken(self, response):
- csrf = re.findall(
- br"",
- response.content
+ csrf = re.findall(br"""