Commits

Stephen McDonald committed e2f8c07

Refactored values for field types in the forms app to separate out classes and widgets.

  • Participants
  • Parent commits 9b1bb54

Comments (0)

Files changed (6)

mezzanine/core/tests.py

 from mezzanine.conf.models import Setting
 from mezzanine.core.models import CONTENT_STATUS_DRAFT
 from mezzanine.core.models import CONTENT_STATUS_PUBLISHED
-from mezzanine.forms.models import Form, FIELD_CHOICES
+from mezzanine.forms import fields
+from mezzanine.forms.models import Form
 from mezzanine.pages.models import ContentPage
 
 
         for required in (True, False):
             form = Form.objects.create(title="Form",
                                        status=CONTENT_STATUS_PUBLISHED)
-            for (i, field) in enumerate(FIELD_CHOICES):
-                form.fields.create(label="Field %s" % i, field_type=field[0],
+            for (i, (field, _)) in enumerate(fields.NAMES):
+                form.fields.create(label="Field %s" % i, field_type=field,
                                    required=required, visible=True)
             response = self.client.get(form.get_absolute_url())
             self.assertEqual(response.status_code, 200)
-            fields = form.fields.visible()
-            data = dict([("field_%s" % f.id, "test") for f in fields])
+            visible_fields = form.fields.visible()
+            data = dict([("field_%s" % f.id, "test") for f in visible_fields])
             response = self.client.post(form.get_absolute_url(), data=data)
             self.assertEqual(response.status_code, 200)
 

mezzanine/forms/fields.py

+
+from django import forms
+from django.forms.extras import SelectDateWidget
+from django.utils.translation import ugettext_lazy as _
+
+
+# Constants for all available field types.
+TEXT = 1
+TEXTAREA = 2
+EMAIL = 3
+CHECKBOX = 4
+CHECKBOX_MULTIPLE = 5
+SELECT = 6
+SELECT_MULTIPLE = 7
+RADIO_MULTIPLE = 8
+FILE = 9
+DATE = 10
+DATE_TIME = 11
+HIDDEN = 12
+
+# Names for all available field types.
+NAMES = (
+    (TEXT, _("Single line text")),
+    (TEXTAREA, _("Multi line text")),
+    (EMAIL, _("Email")),
+    (CHECKBOX, _("Check box")),
+    (CHECKBOX_MULTIPLE, _("Check boxes")),
+    (SELECT, _("Drop down")),
+    (SELECT_MULTIPLE, _("Multi select")),
+    (RADIO_MULTIPLE, _("Radio buttons")),
+    (FILE, _("File upload")),
+    (DATE, _("Date")),
+    (DATE_TIME, _("Date/time")),
+    (HIDDEN, _("Hidden")),
+)
+
+# Field classes for all available field types.
+CLASSES = {
+    TEXT: forms.CharField,
+    TEXTAREA: forms.CharField,
+    EMAIL: forms.EmailField,
+    CHECKBOX: forms.BooleanField,
+    CHECKBOX_MULTIPLE: forms.MultipleChoiceField,
+    SELECT: forms.ChoiceField,
+    SELECT_MULTIPLE: forms.MultipleChoiceField,
+    RADIO_MULTIPLE: forms.ChoiceField,
+    FILE: forms.FileField,
+    DATE: forms.DateField,
+    DATE_TIME: forms.DateTimeField,
+    HIDDEN: forms.CharField,
+}
+
+# Widgets for field types where a specialised widget is required.
+WIDGETS = {
+    TEXTAREA: forms.Textarea,
+    CHECKBOX_MULTIPLE: forms.CheckboxSelectMultiple,
+    RADIO_MULTIPLE: forms.RadioSelect,
+    DATE: SelectDateWidget,
+    HIDDEN: forms.HiddenInput,
+}
+
+# Some helper groupings of field types.
+CHOICES = (CHECKBOX, CHECKBOX_MULTIPLE, SELECT, SELECT_MULTIPLE, RADIO_MULTIPLE)
+DATES = (DATE, DATE_TIME)

mezzanine/forms/fixtures/mezzanine.json

         "pk": 1, 
         "model": "forms.field", 
         "fields": {
-            "field_type": "CharField", 
+            "field_type": 1, 
             "_order": 0, 
             "form": 3,
             "required": true, 
         "pk": 2, 
         "model": "forms.field", 
         "fields": {
-            "field_type": "EmailField", 
+            "field_type": 3, 
             "_order": 1, 
             "form": 3,
             "required": true, 
         "pk": 3, 
         "model": "forms.field", 
         "fields": {
-            "field_type": "ChoiceField", 
+            "field_type": 6, 
             "_order": 2, 
             "form": 3,
             "required": true, 
         "pk": 4, 
         "model": "forms.field", 
         "fields": {
-            "field_type": "CharField/django.forms.Textarea", 
+            "field_type": 2, 
             "_order": 3, 
             "form": 3,
             "required": true, 

mezzanine/forms/forms.py

 from django.utils.importlib import import_module
 from django.utils.translation import ugettext_lazy as _
 
-from mezzanine.conf import settings
+from mezzanine.conf import settings
+from mezzanine.forms import fields
 from mezzanine.forms.models import FormEntry, FieldEntry
 
 
         super(FormForForm, self).__init__(*args, **kwargs)
         for field in self.form_fields:
             field_key = "field_%s" % field.id
-            if "/" in field.field_type:
-                field_class_name, field_widget = field.field_type.split("/")
-            else:
-                field_class_name, field_widget = field.field_type, None
-            field_class = getattr(forms, field_class_name)
+            field_class = fields.CLASSES[field.field_type]
+            field_widget = fields.WIDGETS.get(field.field_type)
             field_args = {"label": field.label, "required": field.required,
-                "help_text": field.help_text}
+                          "help_text": field.help_text}
             arg_names = field_class.__init__.im_func.func_code.co_varnames
             if "max_length" in arg_names:
                 field_args["max_length"] = settings.FORMS_FIELD_MAX_LENGTH
             if "choices" in arg_names:
                 field_args["choices"] = field.get_choices()
             if field_widget is not None:
-                module, widget = field_widget.rsplit(".", 1)
-                field_args["widget"] = getattr(import_module(module), widget)
+                field_args["widget"] = field_widget
             self.initial[field_key] = field.default
             self.fields[field_key] = field_class(**field_args)
             # Add identifying CSS classes to the field.
-            css_class = field_class_name.lower()
+            css_class = field_class.__name__.lower()
             if field.required:
                 css_class += " required"
                 if settings.FORMS_USE_HTML5:
 
     def save(self, **kwargs):
         """
-        Create a FormEntry instance and related FieldEntry instances for each
-        form field.
+        Create a ``FormEntry`` instance and related ``FieldEntry`` 
+        instances for each form field.
         """
         entry = super(FormForForm, self).save(commit=False)
         entry.form = self.form
 
     def email_to(self):
         """
-        Return the value entered for the first field of type EmailField.
+        Return the value entered for the first field of type ``EmailField``.
         """
         for field in self.form_fields:
-            field_class = field.field_type.split("/")[0]
-            if field_class == "EmailField":
+            if field.is_a(fields.EMAIL):
                 return self.cleaned_data["field_%s" % field.id]
         return None
 
             # Checkbox for including in export.
             self.fields["%s_export" % field_key] = forms.BooleanField(
                 label=field.label, initial=True, required=False)
-            is_bool_field = field.field_type == "BooleanField"
-            if "ChoiceField" in field.field_type or is_bool_field:
+            if field.is_a(*fields.CHOICES):
                 # A fixed set of choices to filter by.
-                if is_bool_field:
+                if field.is_a(fields.CHECKBOX):
                     choices = ((True, _("Checked")), (False, _("Not checked")))
                 else:
                     choices = field.get_choices()
                     required=False)
                 self.fields["%s_filter" % field_key] = choice_filter_field
                 self.fields["%s_contains" % field_key] = contains_field
-            elif field.field_type.startswith("Date"):
+            elif field.is_a(*fields.DATES):
                 # A date range to filter by.
                 self.fields["%s_filter" % field_key] = date_filter_field
                 self.fields["%s_from" % field_key] = forms.DateField(
                 contains_field = forms.CharField(label=" ", required=False)
                 self.fields["%s_filter" % field_key] = text_filter_field
                 self.fields["%s_contains" % field_key] = contains_field
-        # Add ``FormEntry.entry_time`` as a field.
+        # Add ``FormEntry.entry_time`` as a field.if field.is_a(fields.EMAIL):
         field_key = "field_0"
         self.fields["%s_export" % field_key] = forms.BooleanField(initial=True,
             label=FormEntry._meta.get_field("entry_time").verbose_name, 
         for field in self.form_fields:
             if self.cleaned_data["field_%s_export" % field.id]:
                 field_indexes[field.id] = len(field_indexes)
-                if field.field_type == "FileField":
+                if field.is_a(fields.FILE):
                     file_field_ids.append(field.id)
-                elif field.field_type.startswith("Date"):
+                elif field.is_a(*fields.DATES):
                     date_field_ids.append(field.id)
         num_columns = len(field_indexes)
         include_entry_time = self.cleaned_data["field_0_export"]

mezzanine/forms/migrations/0003_auto__chg_field_field_field_type.py

+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+    
+    def forwards(self, orm):
+        
+        # Changing field 'Field.field_type'
+        db.alter_column('forms_field', 'field_type', self.gf('django.db.models.fields.IntegerField')())
+    
+    
+    def backwards(self, orm):
+        
+        # Changing field 'Field.field_type'
+        db.alter_column('forms_field', 'field_type', self.gf('django.db.models.fields.CharField')(max_length=55))
+    
+    
+    models = {
+        'core.keyword': {
+            'Meta': {'object_name': 'Keyword'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'forms.field': {
+            'Meta': {'object_name': 'Field'},
+            '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'choices': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'blank': 'True'}),
+            'default': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'blank': 'True'}),
+            'field_type': ('django.db.models.fields.IntegerField', [], {}),
+            'form': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fields'", 'to': "orm['forms.Form']"}),
+            'help_text': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'label': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'placeholder_text': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+            'required': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'})
+        },
+        'forms.fieldentry': {
+            'Meta': {'object_name': 'FieldEntry'},
+            'entry': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fields'", 'to': "orm['forms.FormEntry']"}),
+            'field_id': ('django.db.models.fields.IntegerField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'value': ('django.db.models.fields.CharField', [], {'max_length': '2000'})
+        },
+        'forms.form': {
+            'Meta': {'object_name': 'Form', '_ormbases': ['pages.Page']},
+            'button_text': ('django.db.models.fields.CharField', [], {'default': "u'Submit'", 'max_length': '50'}),
+            'content': ('mezzanine.core.fields.HtmlField', [], {}),
+            'email_copies': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'email_from': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'email_message': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'email_subject': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'page_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['pages.Page']", 'unique': 'True', 'primary_key': 'True'}),
+            'response': ('mezzanine.core.fields.HtmlField', [], {}),
+            'send_email': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'})
+        },
+        'forms.formentry': {
+            'Meta': {'object_name': 'FormEntry'},
+            'entry_time': ('django.db.models.fields.DateTimeField', [], {}),
+            'form': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'entries'", 'to': "orm['forms.Form']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'pages.page': {
+            'Meta': {'object_name': 'Page'},
+            '_keywords': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'content_model': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+            'description': ('mezzanine.core.fields.HtmlField', [], {'blank': 'True'}),
+            'expiry_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'in_footer': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'in_navigation': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'keywords': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['core.Keyword']", 'blank': 'True'}),
+            'login_required': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['pages.Page']"}),
+            'publish_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'short_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'titles': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True'})
+        }
+    }
+    
+    complete_apps = ['forms']

mezzanine/forms/models.py

 from mezzanine.conf import settings
 from mezzanine.core.fields import HtmlField
 from mezzanine.core.models import Orderable, Content
+from mezzanine.forms import fields
 from mezzanine.pages.models import Page
 
 
-FIELD_CHOICES = (
-    ("CharField", _("Single line text")),
-    ("CharField/django.forms.Textarea", _("Multi line text")),
-    ("EmailField", _("Email")),
-    ("BooleanField", _("Check box")),
-    ("MultipleChoiceField/django.forms.CheckboxSelectMultiple", 
-        _("Check boxes")),
-    ("ChoiceField", _("Drop down")),
-    ("MultipleChoiceField", _("Multi select")),
-    ("ChoiceField/django.forms.RadioSelect", _("Radio buttons")),
-    ("FileField", _("File upload")),
-    ("DateField/django.forms.extras.SelectDateWidget", _("Date")),
-    ("DateTimeField", _("Date/time")),
-    ("CharField/django.forms.HiddenInput", _("Hidden")),
-)
-
-
 class Form(Page, Content):
     """
     A user-built form.
     form = models.ForeignKey("Form", related_name="fields")
     label = models.CharField(_("Label"), 
         max_length=settings.FORMS_LABEL_MAX_LENGTH)
-    field_type = models.CharField(_("Type"), choices=FIELD_CHOICES,
-        max_length=55)
+    field_type = models.IntegerField(_("Type"), choices=fields.NAMES)
     required = models.BooleanField(_("Required"), default=True)
     visible = models.BooleanField(_("Visible"), default=True)
     choices = models.CharField(_("Choices"), max_length=1000, blank=True,
         if choice:
             yield choice, choice
 
+    def is_a(self, *args):
+        """
+        Helper that returns True if the field's type is given in any arg.
+        """
+        return self.field_type in args
+
 
 class FormEntry(models.Model):
     """