diff --git a/.travis.yml b/.travis.yml
index 4bf3634e..6676fc36 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,10 @@ env:
- DJANGO_VERSION=https://github.com/django/django/archive/stable/1.11.x.zip
- DJANGO_VERSION=https://github.com/django/django/archive/stable/2.0.x.zip
- DJANGO_VERSION=https://github.com/django/django/archive/stable/2.1.x.zip
+ - DJANGO_VERSION=https://github.com/django/django/archive/stable/2.2.x.zip
+ - DJANGO_VERSION=https://github.com/django/django/archive/stable/3.0.x.zip
+ - DJANGO_VERSION=https://github.com/django/django/archive/stable/3.1.x.zip
+ - DJANGO_VERSION=https://github.com/django/django/archive/stable/3.2.x.zip
python:
- "2.7"
- "3.4"
@@ -17,8 +21,12 @@ matrix:
env: DJANGO_VERSION=https://github.com/django/django/archive/stable/2.0.x.zip
- python: "2.7"
env: DJANGO_VERSION=https://github.com/django/django/archive/stable/2.1.x.zip
+ - python: "2.7"
+ env: DJANGO_VERSION=https://github.com/django/django/archive/stable/2.2.x.zip
- python: "3.4"
env: DJANGO_VERSION=https://github.com/django/django/archive/stable/2.1.x.zip
+ - python: "3.4"
+ env: DJANGO_VERSION=https://github.com/django/django/archive/stable/2.2.x.zip
install:
- pip install $DJANGO_VERSION
- pip install .
diff --git a/forms_builder/example_project/settings.py b/forms_builder/example_project/settings.py
index 27190666..96b33b1b 100644
--- a/forms_builder/example_project/settings.py
+++ b/forms_builder/example_project/settings.py
@@ -75,6 +75,7 @@
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
+ 'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.staticfiles',
diff --git a/forms_builder/example_project/urls.py b/forms_builder/example_project/urls.py
index 78627dd9..9862edca 100644
--- a/forms_builder/example_project/urls.py
+++ b/forms_builder/example_project/urls.py
@@ -1,10 +1,11 @@
from __future__ import unicode_literals
try:
- from django.urls import re_path, include
+ from django.urls import include
except ImportError:
# For Django 1.8 compatibility
- from django.conf.urls import url as re_path, include
+ from django.conf.urls import include
+from django.conf.urls import url
from django.contrib import admin
from django.shortcuts import render
@@ -15,8 +16,8 @@
admin.autodiscover()
urlpatterns = [
- re_path(r'^admin/', admin.site.urls),
- re_path(r'^forms/', include(form_urls)),
- re_path(r'^$', lambda request: render(request, "index.html",
+ url(r'^admin/', admin.site.urls),
+ url(r'^forms/', include(form_urls)),
+ url(r'^$', lambda request: render(request, "index.html",
{"forms": Form.objects.all()})),
]
diff --git a/forms_builder/forms/admin.py b/forms_builder/forms/admin.py
index ed6fee4e..95c0817c 100644
--- a/forms_builder/forms/admin.py
+++ b/forms_builder/forms/admin.py
@@ -9,17 +9,16 @@
from django.contrib import admin
from django.core.files.storage import FileSystemStorage
-try:
- from django.urls import reverse, re_path
-except ImportError:
- # For django 1.8 compatiblity
- from django.conf.urls import url as re_path
- from django.core.urlresolvers import reverse
+from django.urls import re_path
from django.db.models import Count
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
-from django.utils.translation import ungettext, ugettext_lazy as _
-
+from django.utils.translation import ngettext, gettext_lazy as _
+try:
+ from django.urls import reverse
+except ImportError:
+ # For Django 1.8 compatibility
+ from django.core.urlresolvers import reverse
from forms_builder.forms.forms import EntriesForm
from forms_builder.forms.models import Form, Field, FormEntry, FieldEntry
from forms_builder.forms.settings import CSV_DELIMITER, UPLOAD_ROOT
@@ -177,7 +176,7 @@ def info(request, message, fail_silently=True):
count = entries.count()
if count > 0:
entries.delete()
- message = ungettext("1 entry deleted",
+ message = ngettext("1 entry deleted",
"%(count)s entries deleted", count)
info(request, message % {"count": count})
template = "admin/forms/entries.html"
diff --git a/forms_builder/forms/fields.py b/forms_builder/forms/fields.py
index 23d58765..9291c873 100644
--- a/forms_builder/forms/fields.py
+++ b/forms_builder/forms/fields.py
@@ -7,7 +7,7 @@
except ImportError:
# For Django 1.8 compatibility
from django.forms.extras import SelectDateWidget
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from forms_builder.forms.settings import USE_HTML5, EXTRA_FIELDS, EXTRA_WIDGETS
from forms_builder.forms.utils import html5_field, import_attr
diff --git a/forms_builder/forms/forms.py b/forms_builder/forms/forms.py
index b8e3ae53..d04de067 100644
--- a/forms_builder/forms/forms.py
+++ b/forms_builder/forms/forms.py
@@ -20,7 +20,7 @@
from django.core.urlresolvers import reverse
from django.template import Template
from django.utils.safestring import mark_safe
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from forms_builder.forms import fields
from forms_builder.forms.models import FormEntry, FieldEntry
@@ -202,9 +202,9 @@ def __init__(self, form, context, *args, **kwargs):
# Add identifying CSS classes to the field.
css_class = field_class.__name__.lower()
- # Do not add the 'required' field to the CheckboxSelectMultiple because it will
+ # Do not add the 'required' field to the CheckboxSelectMultiple because it will
# mean that all checkboxes have to be checked instead of the usual use case of
- # "at least one".
+ # "at least one".
if field.required and (field_widget != forms.CheckboxSelectMultiple):
css_class += " required"
if settings.USE_HTML5:
diff --git a/forms_builder/forms/models.py b/forms_builder/forms/models.py
index 73c6ae3b..c2600630 100644
--- a/forms_builder/forms/models.py
+++ b/forms_builder/forms/models.py
@@ -11,8 +11,9 @@
from django.db import models
from django.db.models import Q
-from django.utils.encoding import python_2_unicode_compatible
-from django.utils.translation import ugettext, ugettext_lazy as _
+from six import python_2_unicode_compatible
+from django.utils.translation import gettext, gettext_lazy as _
+from django.utils.html import format_html
from future.builtins import str
from forms_builder.forms import fields
@@ -97,6 +98,7 @@ class Meta:
verbose_name = _("Form")
verbose_name_plural = _("Forms")
abstract = True
+ app_label = "forms"
def __str__(self):
return str(self.title)
@@ -123,8 +125,9 @@ def published(self, for_user=None):
status = self.status == STATUS_PUBLISHED
publish_date = self.publish_date is None or self.publish_date <= now()
expiry_date = self.expiry_date is None or self.expiry_date >= now()
- authenticated = for_user is not None and for_user.is_authenticated
- if DJANGO_VERSION <= (1, 9):
+ if DJANGO_VERSION >= (1, 9):
+ authenticated = for_user is not None and for_user.is_authenticated
+ else:
# Django 1.8 compatibility, is_authenticated has to be called as a method.
authenticated = for_user is not None and for_user.is_authenticated()
login_required = (not self.login_required or authenticated)
@@ -139,7 +142,7 @@ def total_entries(self):
total_entries.admin_order_field = "total_entries"
def get_absolute_url(self):
- return reverse("form_detail", kwargs={"slug": self.slug})
+ return reverse("forms:form_detail", kwargs={"slug": self.slug})
def admin_links(self):
kw = {"args": (self.id,)}
@@ -150,9 +153,8 @@ def admin_links(self):
(_("Export all entries"), reverse("admin:form_entries_export", **kw)),
]
for i, (text, url) in enumerate(links):
- links[i] = "%s" % (url, ugettext(text))
- return "
".join(links)
- admin_links.allow_tags = True
+ links[i] = "%s" % (url, gettext(text))
+ return format_html("
".join(links))
admin_links.short_description = ""
@@ -193,6 +195,7 @@ class Meta:
verbose_name = _("Field")
verbose_name_plural = _("Fields")
abstract = True
+ app_label = "forms"
def __str__(self):
return str(self.label)
@@ -239,6 +242,7 @@ class Meta:
verbose_name = _("Form entry")
verbose_name_plural = _("Form entries")
abstract = True
+ app_label = "forms"
class AbstractFieldEntry(models.Model):
@@ -254,6 +258,7 @@ class Meta:
verbose_name = _("Form field entry")
verbose_name_plural = _("Form field entries")
abstract = True
+ app_label = "forms"
###################################################
diff --git a/forms_builder/forms/signals.py b/forms_builder/forms/signals.py
index 7da541e0..e179f1ac 100644
--- a/forms_builder/forms/signals.py
+++ b/forms_builder/forms/signals.py
@@ -2,5 +2,5 @@
from django.dispatch import Signal
-form_invalid = Signal(providing_args=["form"])
-form_valid = Signal(providing_args=["form", "entry"])
+form_invalid = Signal()
+form_valid = Signal()
diff --git a/forms_builder/forms/urls.py b/forms_builder/forms/urls.py
index 6cc93d95..6adcf482 100644
--- a/forms_builder/forms/urls.py
+++ b/forms_builder/forms/urls.py
@@ -1,12 +1,10 @@
from __future__ import unicode_literals
-try:
- from django.urls import re_path
-except ImportError:
- # For Django 1.8 compatibility
- from django.conf.urls import url as re_path
+
+from django.urls import re_path
from forms_builder.forms import views
+app_name="forms"
urlpatterns = [
re_path(r"(?P.*)/sent/$", views.form_sent, name="form_sent"),
diff --git a/forms_builder/forms/views.py b/forms_builder/forms/views.py
index ac484f45..2a04810f 100644
--- a/forms_builder/forms/views.py
+++ b/forms_builder/forms/views.py
@@ -10,11 +10,11 @@
# For Django 1.8 compatibility
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseBadRequest
-from django.shortcuts import get_object_or_404, redirect, render_to_response
+from django.shortcuts import get_object_or_404, redirect, render
from django.template import RequestContext
-from django.utils.http import urlquote
from django.views.generic.base import TemplateView
from email_extras.utils import send_mail_template
+from urllib.parse import quote
from forms_builder.forms.forms import FormForForm
from forms_builder.forms.models import Form
@@ -37,10 +37,10 @@ def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
login_required = context["form"].login_required
if login_required and not request.user.is_authenticated:
- path = urlquote(request.get_full_path())
+ path = quote(request.get_full_path())
bits = (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path)
return redirect("%s?%s=%s" % bits)
- return self.render_to_response(context)
+ return self.render(request, context)
def post(self, request, *args, **kwargs):
published = Form.objects.published(for_user=request.user)
@@ -60,14 +60,14 @@ def post(self, request, *args, **kwargs):
entry = form_for_form.save()
form_valid.send(sender=request, form=form_for_form, entry=entry)
self.send_emails(request, form_for_form, form, entry, attachments)
- if not self.request.is_ajax():
+ if not self.request.headers.get("x-requested-with") == "XMLHttpRequest": # is_ajax
return redirect(form.redirect_url or
- reverse("form_sent", kwargs={"slug": form.slug}))
+ reverse("forms:form_sent", kwargs={"slug": form.slug}))
context = {"form": form, "form_for_form": form_for_form}
- return self.render_to_response(context)
+ return self.render(request, context)
- def render_to_response(self, context, **kwargs):
- if self.request.method == "POST" and self.request.is_ajax():
+ def render(self, request, context, **kwargs):
+ if self.request.method == "POST" and self.request.headers.get("x-requested-with") == "XMLHttpRequest": # is_ajax
json_context = json.dumps({
"errors": context["form_for_form"].errors,
"form": context["form_for_form"].as_p(),
@@ -120,4 +120,4 @@ def form_sent(request, slug, template="forms/form_sent.html"):
"""
published = Form.objects.published(for_user=request.user)
context = {"form": get_object_or_404(published, slug=slug)}
- return render_to_response(template, context, RequestContext(request))
+ return render(request, template, context=context)
diff --git a/setup.py b/setup.py
index 43d9bc11..1f7367ca 100644
--- a/setup.py
+++ b/setup.py
@@ -50,7 +50,7 @@
"sphinx-me >= 0.1.2",
"unidecode",
"django-email-extras >= 0.2",
- "django >= 1.8, < 2.2",
+ "django >= 1.9, <4.2",
"future <= 0.15.0",
],
classifiers = [