diff --git a/.gitignore b/.gitignore index e3a53f70..589391f0 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ local_settings.py build/ dist/ forms_builder/example_project/static/ +formproject/ diff --git a/forms_builder/example_project/manage.py b/forms_builder/example_project/manage.py old mode 100755 new mode 100644 diff --git a/forms_builder/forms/forms.py b/forms_builder/forms/forms.py index b8e3ae53..9ef7be74 100644 --- a/forms_builder/forms/forms.py +++ b/forms_builder/forms/forms.py @@ -202,10 +202,7 @@ 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 - # mean that all checkboxes have to be checked instead of the usual use case of - # "at least one". - if field.required and (field_widget != forms.CheckboxSelectMultiple): + if field.required: css_class += " required" if settings.USE_HTML5: # Except Django version 1.10 this is necessary for all versions from 1.8 to 1.11. diff --git a/forms_builder/forms/migrations/0001_initial.py b/forms_builder/forms/migrations/0001_initial.py index 32382e44..bab0ebb4 100644 --- a/forms_builder/forms/migrations/0001_initial.py +++ b/forms_builder/forms/migrations/0001_initial.py @@ -3,7 +3,7 @@ from django.db import models, migrations -from forms_builder.forms import fields, settings +from forms_builder.forms import settings class Migration(migrations.Migration): @@ -19,7 +19,7 @@ class Migration(migrations.Migration): ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('label', models.CharField(max_length=200, verbose_name='Label')), ('slug', models.SlugField(default='', max_length=100, verbose_name='Slug', blank=True)), - ('field_type', models.IntegerField(verbose_name='Type', choices=fields.NAMES)), + ('field_type', models.IntegerField(verbose_name='Type', choices=[(1, 'Single line text'), (2, 'Multi line text'), (3, 'Email'), (13, 'Number'), (14, 'URL'), (4, 'Check box'), (5, 'Check boxes'), (6, 'Drop down'), (7, 'Multi select'), (8, 'Radio buttons'), (9, 'File upload'), (10, 'Date'), (11, 'Date/time'), (15, 'Date of birth'), (12, 'Hidden')])), ('required', models.BooleanField(default=True, verbose_name='Required')), ('visible', models.BooleanField(default=True, verbose_name='Visible')), ('choices', models.CharField(help_text='Comma separated options where applicable. If an option itself contains commas, surround the option starting with the `character and ending with the ` character.', max_length=1000, verbose_name='Choices', blank=True)), diff --git a/forms_builder/forms/migrations/0003_auto_20180522_0820.py b/forms_builder/forms/migrations/0003_auto_20180522_0820.py deleted file mode 100644 index 11499e76..00000000 --- a/forms_builder/forms/migrations/0003_auto_20180522_0820.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.0.4 on 2018-05-22 08:20 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('forms', '0002_auto_20160418_0120'), - ] - - operations = [ - migrations.AlterField( - model_name='field', - name='slug', - field=models.SlugField(blank=True, default='', max_length=2000, verbose_name='Slug'), - ), - ] diff --git a/forms_builder/forms/models.py b/forms_builder/forms/models.py index 73c6ae3b..ff399bbb 100644 --- a/forms_builder/forms/models.py +++ b/forms_builder/forms/models.py @@ -2,6 +2,7 @@ from django import VERSION as DJANGO_VERSION from django.contrib.sites.models import Site +from django.core.exceptions import ValidationError try: from django.urls import reverse @@ -11,7 +12,7 @@ from django.db import models from django.db.models import Q -from django.utils.encoding import python_2_unicode_compatible +from six import python_2_unicode_compatible from django.utils.translation import ugettext, ugettext_lazy as _ from future.builtins import str @@ -138,8 +139,9 @@ def total_entries(self): return self.total_entries total_entries.admin_order_field = "total_entries" + # @models.permalink def get_absolute_url(self): - return reverse("form_detail", kwargs={"slug": self.slug}) + return reverse("form_detail", args=(self.slug,)) def admin_links(self): kw = {"args": (self.id,)} @@ -171,7 +173,7 @@ class AbstractField(models.Model): """ label = models.CharField(_("Label"), max_length=settings.LABEL_MAX_LENGTH) - slug = models.SlugField(_('Slug'), max_length=2000, blank=True, + slug = models.SlugField(_('Slug'), max_length=100, blank=True, default="") field_type = models.IntegerField(_("Type"), choices=fields.NAMES) required = models.BooleanField(_("Required"), default=True) diff --git a/forms_builder/forms/tests.py b/forms_builder/forms/tests.py index ace512b0..ed6e3c6e 100644 --- a/forms_builder/forms/tests.py +++ b/forms_builder/forms/tests.py @@ -126,14 +126,6 @@ def test_field_validate_slug_names(self): except IntegrityError: self.fail("Slugs were not auto-unique") - def test_field_validate_slug_length(self): - max_slug_length = 2000 - form = Form.objects.create(title="Test") - field = Field(form=form, - label='x' * (max_slug_length + 1), field_type=NAMES[0][0]) - field.save() - self.assertLessEqual(len(field.slug), max_slug_length) - def test_field_default_ordering(self): form = Form.objects.create(title="Test") form.fields.create(label="second field", diff --git a/forms_builder/forms/utils.py b/forms_builder/forms/utils.py index f8f6a74b..58063c8b 100644 --- a/forms_builder/forms/utils.py +++ b/forms_builder/forms/utils.py @@ -27,16 +27,12 @@ def unique_slug(manager, slug_field, slug): Ensure slug is unique for the given manager, appending a digit if it isn't. """ - max_length = manager.model._meta.get_field(slug_field).max_length - slug = slug[:max_length] i = 0 while True: if i > 0: if i > 1: slug = slug.rsplit("-", 1)[0] - # We need to keep the slug length under the slug fields max length. We need to - # account for the length that is added by adding a random integer and `-`. - slug = "%s-%s" % (slug[:max_length - len(str(i)) - 1], i) + slug = "%s-%s" % (slug, i) if not manager.filter(**{slug_field: slug}): break i += 1 diff --git a/forms_builder/forms/views.py b/forms_builder/forms/views.py index ac484f45..93d7fa5d 100644 --- a/forms_builder/forms/views.py +++ b/forms_builder/forms/views.py @@ -10,7 +10,7 @@ # 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 @@ -36,7 +36,7 @@ def get_context_data(self, **kwargs): 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: + if login_required and not request.user.is_authenticated(): path = urlquote(request.get_full_path()) bits = (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path) return redirect("%s?%s=%s" % bits) @@ -120,4 +120,5 @@ 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(template, context) + return HttpResponse("Form submitted") diff --git a/setup.py b/setup.py index 43d9bc11..b5e8733e 100644 --- a/setup.py +++ b/setup.py @@ -50,8 +50,9 @@ "sphinx-me >= 0.1.2", "unidecode", "django-email-extras >= 0.2", - "django >= 1.8, < 2.2", + "django >= 2.0", "future <= 0.15.0", + "six" ], classifiers = [ "Development Status :: 5 - Production/Stable",