diff --git a/django_remote_forms/fields.py b/django_remote_forms/fields.py index 4e0d33a..d6de00d 100644 --- a/django_remote_forms/fields.py +++ b/django_remote_forms/fields.py @@ -6,6 +6,7 @@ from django_remote_forms import logger, widgets +from django.utils.translation import gettext as _ class RemoteField(object): """ @@ -24,12 +25,16 @@ def __init__(self, field, form_initial_data=None, field_name=None): self.field = field self.form_initial_data = form_initial_data + @property + def initial(self): + return self.form_initial_data or self.field.initial + def as_dict(self): field_dict = OrderedDict() field_dict['title'] = self.field.__class__.__name__ field_dict['required'] = self.field.required - field_dict['label'] = self.field.label - field_dict['initial'] = self.form_initial_data or self.field.initial + field_dict['label'] = _(self.field.label) + field_dict['initial'] = self.initial field_dict['help_text'] = self.field.help_text field_dict['error_messages'] = self.field.error_messages @@ -37,10 +42,13 @@ def as_dict(self): # Instantiate the Remote Forms equivalent of the widget if possible # in order to retrieve the widget contents as a dictionary. remote_widget_class_name = 'Remote%s' % self.field.widget.__class__.__name__ + if hasattr(self.field.widget, 'parent_class'): + remote_widget_class_name = 'Remote%s' % self.field.widget.parent_class + try: remote_widget_class = getattr(widgets, remote_widget_class_name) remote_widget = remote_widget_class(self.field.widget, field_name=self.field_name) - except Exception, e: + except Exception as e: logger.warning('Error serializing %s: %s', remote_widget_class_name, str(e)) widget_dict = {} else: @@ -48,6 +56,9 @@ def as_dict(self): field_dict['widget'] = widget_dict + if hasattr(self.field.widget, 'input_type'): + field_dict['widget']['input_type'] = self.field.widget.input_type + return field_dict @@ -76,6 +87,12 @@ def as_dict(self): class RemoteFloatField(RemoteIntegerField): + @property + def initial(self): + if type(self.form_initial_data) == float: + return self.form_initial_data + return self.field.initial + def as_dict(self): return super(RemoteFloatField, self).as_dict() @@ -103,14 +120,22 @@ def as_dict(self): field_dict['initial'] = field_dict['initial']() # If initial value is datetime then convert it using first available input format + if (isinstance(field_dict['initial'], (datetime.datetime, datetime.time, datetime.date))): - if not len(field_dict['input_formats']): - if isinstance(field_dict['initial'], datetime.date): + # Hotfix to check input formats + input_formats = field_dict.get('input_formats', []) + try: + has_input_formats = input_formats[0] is not None + except Exception as _: + has_input_formats = False + + if not has_input_formats: + if isinstance(field_dict['initial'], datetime.datetime): + field_dict['input_formats'] = settings.DATETIME_INPUT_FORMATS + elif isinstance(field_dict['initial'], datetime.date): field_dict['input_formats'] = settings.DATE_INPUT_FORMATS elif isinstance(field_dict['initial'], datetime.time): field_dict['input_formats'] = settings.TIME_INPUT_FORMATS - elif isinstance(field_dict['initial'], datetime.datetime): - field_dict['input_formats'] = settings.DATETIME_INPUT_FORMATS input_format = field_dict['input_formats'][0] field_dict['initial'] = field_dict['initial'].strftime(input_format) @@ -148,6 +173,7 @@ def as_dict(self): field_dict = super(RemoteFileField, self).as_dict() field_dict['max_length'] = self.field.max_length + field_dict['initial'] = str(field_dict['initial']) if field_dict['initial'] is not None else None return field_dict @@ -173,22 +199,26 @@ def as_dict(self): class RemoteChoiceField(RemoteField): - def as_dict(self): - field_dict = super(RemoteChoiceField, self).as_dict() - - field_dict['choices'] = [] - for key, value in self.field.choices: - field_dict['choices'].append({ - 'value': key, - 'display': value - }) - - return field_dict + pass class RemoteModelChoiceField(RemoteChoiceField): def as_dict(self): - return super(RemoteModelChoiceField, self).as_dict() + form_as_dict = super(RemoteModelChoiceField, self).as_dict() + + field = self.__dict__.get('field', {}) + if hasattr(field, '_queryset'): + queryset = self.__dict__['field'].__dict__['_queryset'] + model = queryset.model() + app_name = model.app_name if hasattr(model, 'app_name') else None + model_name = model.model_name if hasattr(model, 'model_name') else None + + form_as_dict.update({ + 'app_name' : app_name, + 'model_name' : model_name, + }) + + return form_as_dict class RemoteTypedChoiceField(RemoteChoiceField): @@ -210,7 +240,21 @@ def as_dict(self): class RemoteModelMultipleChoiceField(RemoteMultipleChoiceField): def as_dict(self): - return super(RemoteModelMultipleChoiceField, self).as_dict() + form_as_dict = super(RemoteModelMultipleChoiceField, self).as_dict() + + field = self.__dict__.get('field', {}) + if hasattr(field, '_queryset'): + queryset = self.__dict__['field'].__dict__['_queryset'] + model = queryset.model() + app_name = model.app_name if hasattr(model, 'app_name') else None + model_name = model.model_name if hasattr(model, 'model_name') else None + + form_as_dict.update({ + 'app_name' : app_name, + 'model_name' : model_name, + }) + + return form_as_dict class RemoteTypedMultipleChoiceField(RemoteMultipleChoiceField): diff --git a/django_remote_forms/forms.py b/django_remote_forms/forms.py index 26b38fb..ae5a796 100644 --- a/django_remote_forms/forms.py +++ b/django_remote_forms/forms.py @@ -10,6 +10,7 @@ def __init__(self, form, *args, **kwargs): self.all_fields = set(self.form.fields.keys()) + self.title = kwargs.pop('title', None) self.excluded_fields = set(kwargs.pop('exclude', [])) self.included_fields = set(kwargs.pop('include', [])) self.readonly_fields = set(kwargs.pop('readonly', [])) @@ -108,7 +109,8 @@ def as_dict(self): } """ form_dict = OrderedDict() - form_dict['title'] = self.form.__class__.__name__ + + form_dict['title'] = self.title if self.title else self.form.__class__.__name__ form_dict['non_field_errors'] = self.form.non_field_errors() form_dict['label_suffix'] = self.form.label_suffix form_dict['is_bound'] = self.form.is_bound @@ -122,7 +124,7 @@ def as_dict(self): initial_data = {} - for name, field in [(x, self.form.fields[x]) for x in self.fields]: + for name, field in [(x, self.form.fields[x]) for x in self.fields]: # Retrieve the initial data from the form itself if it exists so # that we properly handle which initial data should be returned in # the dictionary. @@ -138,7 +140,7 @@ def as_dict(self): try: remote_field_class = getattr(fields, remote_field_class_name) remote_field = remote_field_class(field, form_initial_field_data, field_name=name) - except Exception, e: + except Exception as e: logger.warning('Error serializing field %s: %s', remote_field_class_name, str(e)) field_dict = {} else: @@ -153,11 +155,14 @@ def as_dict(self): if 'initial' not in form_dict['fields'][name]: form_dict['fields'][name]['initial'] = None - initial_data[name] = form_dict['fields'][name]['initial'] + # Remove the coerce key from the field, it will not be used + if form_dict['fields'][name].get('coerce'): + form_dict['fields'][name].pop('coerce') + initial_data[name] = form_dict['fields'][name]['initial'] if self.form.data: form_dict['data'] = self.form.data else: form_dict['data'] = initial_data - + return resolve_promise(form_dict) diff --git a/django_remote_forms/utils.py b/django_remote_forms/utils.py index 0391fa0..af30401 100644 --- a/django_remote_forms/utils.py +++ b/django_remote_forms/utils.py @@ -1,16 +1,19 @@ from django.utils.functional import Promise -from django.utils.encoding import force_unicode - +from django.utils.encoding import force_text +from django.forms.models import ModelChoiceIteratorValue +from django.db import models def resolve_promise(o): if isinstance(o, dict): for k, v in o.items(): o[k] = resolve_promise(v) + if isinstance(o[k], ModelChoiceIteratorValue): + o[k] = getattr(o[k], 'value') elif isinstance(o, (list, tuple)): o = [resolve_promise(x) for x in o] elif isinstance(o, Promise): try: - o = force_unicode(o) + o = force_text(o) except: # Item could be a lazy tuple or list try: @@ -19,5 +22,9 @@ def resolve_promise(o): raise Exception('Unable to resolve lazy object %s' % o) elif callable(o): o = o() - + elif isinstance(o, models.Model): # New treatment for models instances, return the model instance id + try: + o = o.id + except Exception as e: + print(e) return o diff --git a/django_remote_forms/widgets.py b/django_remote_forms/widgets.py index d66a3fb..7b35bcc 100644 --- a/django_remote_forms/widgets.py +++ b/django_remote_forms/widgets.py @@ -18,6 +18,32 @@ def as_dict(self): widget_dict['is_required'] = self.widget.is_required widget_dict['attrs'] = self.widget.attrs + if hasattr(self.widget, 'related_field'): + widget_dict['related_field'] = self.widget.related_field + + if hasattr(self.widget, 'choices'): + widget_dict['choices'] = widget_dict.get('choices', []) + if type(self.widget.choices) is list: + self.widget.choices = self.widget.choices + elif type(self.widget.choices) is tuple: + self.widget.choices = list(self.widget.choices) + else: + print(self.widget.choices) + print(f"Unable to parse type {type(self.widget.choices)} for widget choices") + widget_dict['choices'] = [] + self.widget.choices = [] + + for key, value, *data in self.widget.choices: + complementary_data = {} + if len(data) and type(data[0]) is dict: + complementary_data = data[0] + + widget_dict['choices'].append(dict( + **complementary_data, + value = key, + display = value + )) + return widget_dict @@ -166,13 +192,6 @@ class RemoteSelect(RemoteWidget): def as_dict(self): widget_dict = super(RemoteSelect, self).as_dict() - widget_dict['choices'] = [] - for key, value in self.widget.choices: - widget_dict['choices'].append({ - 'value': key, - 'display': value - }) - widget_dict['input_type'] = 'select' return widget_dict @@ -188,7 +207,7 @@ def as_dict(self): widget_dict = super(RemoteSelectMultiple, self).as_dict() widget_dict['input_type'] = 'selectmultiple' - widget_dict['size'] = len(widget_dict['choices']) + widget_dict['size'] = len(widget_dict.get('choices', [])) return widget_dict