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 = [