diff --git a/mongodbforms/documents.py b/mongodbforms/documents.py index 0a432a89..79fa7554 100644 --- a/mongodbforms/documents.py +++ b/mongodbforms/documents.py @@ -8,7 +8,14 @@ from django.forms.widgets import media_property from django.core.exceptions import FieldError from django.core.validators import EMPTY_VALUES -from django.forms.util import ErrorList + +if (django.get_version() < '1.8'): + # Compatibility with django earlier version + from django.forms.util import ErrorList +else: + # Compatibility with django newest version + from django.forms.utils import ErrorList + from django.forms.formsets import BaseFormSet, formset_factory from django.utils.translation import ugettext_lazy as _, ugettext from django.utils.text import capfirst, get_valid_filename diff --git a/mongodbforms/fieldgenerator.py b/mongodbforms/fieldgenerator.py index f4d842e3..707b1279 100644 --- a/mongodbforms/fieldgenerator.py +++ b/mongodbforms/fieldgenerator.py @@ -14,7 +14,11 @@ try: from django.utils.encoding import smart_unicode except ImportError: - from django.forms.util import smart_unicode + if (django.get_version() < '1.8'): + from django.forms.util import smart_unicode + else: + from django.forms.utils import smart_unicode + from django.utils.text import capfirst from mongoengine import (ReferenceField as MongoReferenceField, @@ -34,14 +38,14 @@ class MongoFormFieldGenerator(object): """This class generates Django form-fields for mongoengine-fields.""" - + # used for fields that fit in one of the generate functions # but don't actually have the name. generator_map = { 'sortedlistfield': 'generate_listfield', 'longfield': 'generate_intfield', } - + form_field_map = { 'stringfield': MongoCharField, 'stringfield_choices': forms.TypedChoiceField, @@ -63,12 +67,12 @@ class MongoFormFieldGenerator(object): 'filefield': forms.FileField, 'imagefield': forms.ImageField, } - + # uses the same keys as form_field_map widget_override_map = { 'stringfield_long': forms.Textarea, } - + def __init__(self, field_overrides={}, widget_overrides={}): self.form_field_map.update(field_overrides) self.widget_override_map.update(widget_overrides) @@ -83,14 +87,14 @@ def generate(self, field, **kwargs): # to handle then a simple field if isinstance(field, MongoEmbeddedDocumentField): return - + attr_name = 'generate_%s' % field.__class__.__name__.lower() if hasattr(self, attr_name): return getattr(self, attr_name)(field, **kwargs) for cls in field.__class__.__bases__: cls_name = cls.__name__.lower() - + attr_name = 'generate_%s' % cls_name if hasattr(self, attr_name): return getattr(self, attr_name)(field, **kwargs) @@ -98,7 +102,7 @@ def generate(self, field, **kwargs): if cls_name in self.form_field_map: attr = self.generator_map.get(cls_name) return getattr(self, attr)(field, **kwargs) - + raise NotImplementedError('%s is not supported by MongoForm' % field.__class__.__name__) @@ -134,7 +138,7 @@ def get_field_help_text(self, field): return field.help_text else: return '' - + def get_field_default(self, field): if isinstance(field, (MongoListField, MongoMapField)): f = field.field @@ -148,7 +152,7 @@ def get_field_default(self, field): else: d['initial'] = field.default return f.default - + def check_widget(self, map_key): if map_key in self.widget_override_map: return {'widget': self.widget_override_map.get(map_key)} @@ -181,7 +185,7 @@ def generate_stringfield(self, field, **kwargs): }) if field.regex: defaults['validators'] = [RegexValidator(regex=field.regex)] - + form_class = self.form_field_map.get(map_key) defaults.update(self.check_widget(map_key)) defaults.update(kwargs) @@ -324,7 +328,7 @@ def generate_listfield(self, field, **kwargs): # So we just ignore them if isinstance(field.field, MongoEmbeddedDocumentField): return - + defaults = { 'label': self.get_field_label(field), 'help_text': self.get_field_help_text(field), @@ -351,13 +355,13 @@ def generate_listfield(self, field, **kwargs): defaults.update(self.check_widget(map_key)) defaults.update(kwargs) return form_class(**defaults) - + def generate_mapfield(self, field, **kwargs): # We can't really handle embedded documents here. # So we just ignore them if isinstance(field.field, MongoEmbeddedDocumentField): return - + map_key = 'mapfield' form_field = self.generate(field.field) defaults = { @@ -433,10 +437,10 @@ def check_widget(self, map_key): override = super(Html5FormFieldGenerator, self).check_widget(map_key) if override != {}: return override - + chunks = map_key.split('field') kind = chunks[0] - + if kind == 'email': if hasattr(forms, 'EmailInput'): return {'widget': forms.EmailInput} diff --git a/mongodbforms/fields.py b/mongodbforms/fields.py index 6f4817d4..cb785fb9 100644 --- a/mongodbforms/fields.py +++ b/mongodbforms/fields.py @@ -14,24 +14,30 @@ from django.utils.encoding import force_text as force_unicode except ImportError: from django.utils.encoding import force_unicode - + try: from django.utils.encoding import smart_text as smart_unicode except ImportError: try: from django.utils.encoding import smart_unicode except ImportError: - from django.forms.util import smart_unicode - + if (django.get_version() < '1.8'): + from django.forms.util import smart_unicode + else: + from django.forms.utils import smart_unicode + from django.utils.translation import ugettext_lazy as _ -from django.forms.util import ErrorList +if (django.get_version() < '1.8'): + from django.forms.util import ErrorList +else: + from django.forms.utils import ErrorList from django.core.exceptions import ValidationError try: # objectid was moved into bson in pymongo 1.9 from bson.errors import InvalidId except ImportError: from pymongo.errors import InvalidId - + from mongodbforms.widgets import ListWidget, MapWidget, HiddenMapWidget @@ -66,23 +72,23 @@ def to_python(self, value): if value in EMPTY_VALUES: return None return value - - + + class MongoCharField(NormalizeValueMixin, forms.CharField): pass - + class MongoEmailField(NormalizeValueMixin, forms.EmailField): pass - + class MongoSlugField(NormalizeValueMixin, forms.SlugField): pass - + class MongoURLField(NormalizeValueMixin, forms.URLField): pass - + class ReferenceField(forms.ChoiceField): """ @@ -96,7 +102,7 @@ def __init__(self, queryset, empty_label="---------", *args, **kwargs): def _get_queryset(self): return self._queryset.clone() - + def _set_queryset(self, queryset): self._queryset = queryset self.widget.choices = self.choices @@ -130,7 +136,7 @@ def clean(self, value): return None oid = super(ReferenceField, self).clean(value) - + try: obj = self.queryset.get(pk=oid) except (TypeError, InvalidId, self.queryset._document.DoesNotExist): @@ -138,7 +144,7 @@ def clean(self, value): self.error_messages['invalid_choice'] % {'value': value} ) return obj - + def __deepcopy__(self, memo): result = super(forms.ChoiceField, self).__deepcopy__(memo) result.queryset = self.queryset # self.queryset calls clone() @@ -169,7 +175,7 @@ def clean(self, value): return [] if not isinstance(value, (list, tuple)): raise forms.ValidationError(self.error_messages['list']) - + qs = self.queryset try: qs = qs.filter(pk__in=value) @@ -193,8 +199,8 @@ def prepare_value(self, value): sup = super(DocumentMultipleChoiceField, self) return [sup.prepare_value(v) for v in value] return super(DocumentMultipleChoiceField, self).prepare_value(value) - - + + class ListField(forms.Field): default_error_messages = { 'invalid': _('Enter a list of values.'), @@ -205,23 +211,23 @@ class ListField(forms.Field): def __init__(self, contained_field, *args, **kwargs): if 'widget' in kwargs: self.widget = kwargs.pop('widget') - + if isinstance(contained_field, type): contained_widget = contained_field().widget else: contained_widget = contained_field.widget - + if isinstance(contained_widget, type): contained_widget = contained_widget() self.widget = self.widget(contained_widget) - + super(ListField, self).__init__(*args, **kwargs) - + if isinstance(contained_field, type): self.contained_field = contained_field(required=self.required) else: self.contained_field = contained_field - + if not hasattr(self, 'empty_values'): self.empty_values = list(EMPTY_VALUES) @@ -241,7 +247,7 @@ def clean(self, value): return [] else: raise ValidationError(self.error_messages['invalid']) - + for field_value in value: try: clean_data.append(self.contained_field.clean(field_value)) @@ -262,12 +268,12 @@ def clean(self, value): def _has_changed(self, initial, data): if initial is None: initial = ['' for x in range(0, len(data))] - + for initial, data in zip(initial, data): if self.contained_field._has_changed(initial, data): return True return False - + def prepare_value(self, value): value = [] if value is None else value value = super(ListField, self).prepare_value(value) @@ -290,30 +296,30 @@ def __init__(self, contained_field, max_key_length=None, *args, **kwargs): if 'widget' in kwargs: self.widget = kwargs.pop('widget') - + if isinstance(contained_field, type): contained_widget = contained_field().widget else: contained_widget = contained_field.widget - + if isinstance(contained_widget, type): contained_widget = contained_widget() self.widget = self.widget(contained_widget) - + super(MapField, self).__init__(*args, **kwargs) - + if isinstance(contained_field, type): field_kwargs['required'] = self.required self.contained_field = contained_field(**field_kwargs) else: self.contained_field = contained_field - + self.key_validators = key_validators if min_key_length is not None: self.key_validators.append(MinLengthValidator(int(min_key_length))) if max_key_length is not None: self.key_validators.append(MaxLengthValidator(int(max_key_length))) - + # type of field used to store the dicts value if not hasattr(self, 'empty_values'): self.empty_values = list(EMPTY_VALUES) @@ -351,13 +357,13 @@ def clean(self, value): return {} else: raise ValidationError(self.error_messages['invalid']) - + # sort out required => at least one element must be in there for key, val in value.items(): # ignore empties. Can they even come up here? if key in self.empty_values and val in self.empty_values: continue - + try: val = self.contained_field.clean(val) except ValidationError as e: @@ -365,7 +371,7 @@ def clean(self, value): # raise at the end of clean(), rather than raising a single # exception for the first error we encounter. errors.extend(e.messages) - + try: self._validate_key(key) except ValidationError as e: @@ -373,12 +379,12 @@ def clean(self, value): # raise at the end of clean(), rather than raising a single # exception for the first error we encounter. errors.extend(e.messages) - + clean_data[key] = val - + if self.contained_field.required: self.contained_field.required = False - + if errors: raise ValidationError(errors) diff --git a/mongodbforms/widgets.py b/mongodbforms/widgets.py index 77acbc12..7ec4d66d 100644 --- a/mongodbforms/widgets.py +++ b/mongodbforms/widgets.py @@ -5,7 +5,10 @@ MultiWidget, HiddenInput) from django.utils.safestring import mark_safe from django.core.validators import EMPTY_VALUES -from django.forms.util import flatatt +if (django.get_version() < '1.8'): + from django.forms.util import flatatt +else: + from django.forms.util import flatatt class Html5SplitDateTimeWidget(SplitDateTimeWidget): @@ -25,13 +28,13 @@ def __init__(self, data_widget, attrs=None): self.data_widget = data_widget self.data_widget.is_localized = self.is_localized super(BaseContainerWidget, self).__init__(attrs) - + def id_for_label(self, id_): # See the comment for RadioSelect.id_for_label() if id_: id_ += '_0' return id_ - + def format_output(self, rendered_widgets): """ Given a list of rendered widgets (as strings), returns a Unicode string @@ -51,7 +54,7 @@ def _get_media(self): media = media + self.data_widget.media return media media = property(_get_media) - + def __deepcopy__(self, memo): obj = super(BaseContainerWidget, self).__deepcopy__(memo) obj.data_widget = copy.deepcopy(self.data_widget) @@ -64,7 +67,7 @@ def render(self, name, value, attrs=None): raise TypeError( "Value supplied for %s must be a list or tuple." % name ) - + output = [] value = [] if value is None else value final_attrs = self.build_attrs(attrs) @@ -103,12 +106,12 @@ def __init__(self, data_widget, attrs=None): def render(self, name, value, attrs=None): if value is not None and not isinstance(value, dict): raise TypeError("Value supplied for %s must be a dict." % name) - + output = [] final_attrs = self.build_attrs(attrs) id_ = final_attrs.get('id', None) fieldset_attr = {} - + # in Python 3.X dict.items() returns dynamic *view objects* value = list(value.items()) value.append(('', '')) @@ -120,13 +123,13 @@ def render(self, name, value, attrs=None): group = [] if not self.is_hidden: group.append(mark_safe('
')) - + output.append(mark_safe(''.join(group))) return mark_safe(self.format_output(output)) @@ -168,10 +171,10 @@ def __deepcopy__(self, memo): obj.key_widget = copy.deepcopy(self.key_widget) return obj - + class HiddenMapWidget(MapWidget): is_hidden = True - + def __init__(self, attrs=None): data_widget = HiddenInput() super(MapWidget, self).__init__(data_widget, attrs)