from django import forms from django.http import QueryDict from rest_framework import serializers class FormFieldWrapperField(serializers.Field): def __init__(self, *args, **kwargs): self.form_field = kwargs.pop('form_field') super().__init__(*args, **kwargs) def to_representation(self, value): return self.form_field.widget.format_value(value) def to_internal_value(self, data): d = self.form_field.widget.value_from_datadict({'name': data}, {}, 'name') d = self.form_field.clean(d) return d simple_mappings = ( (forms.DateField, serializers.DateField, tuple()), (forms.TimeField, serializers.TimeField, tuple()), (forms.SplitDateTimeField, serializers.DateTimeField, tuple()), (forms.DateTimeField, serializers.DateTimeField, tuple()), (forms.DecimalField, serializers.DecimalField, ('max_digits', 'decimal_places', 'min_value', 'max_value')), (forms.FloatField, serializers.FloatField, tuple()), (forms.IntegerField, serializers.IntegerField, tuple()), (forms.EmailField, serializers.EmailField, tuple()), (forms.UUIDField, serializers.UUIDField, tuple()), (forms.URLField, serializers.URLField, tuple()), (forms.NullBooleanField, serializers.NullBooleanField, tuple()), (forms.BooleanField, serializers.BooleanField, tuple()), ) class SerializerDescriptionField(serializers.Field): def to_representation(self, value): fields = [] for k, v in value.fields.items(): d = { 'name': k, 'required': v.required, } if isinstance(v, serializers.ChoiceField): d['choices'] = list(v.choices.keys()) fields.append(d) return fields class ExporterSerializer(serializers.Serializer): identifier = serializers.CharField() verbose_name = serializers.CharField() input_parameters = SerializerDescriptionField(source='_serializer') class PrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField): def to_representation(self, value): if isinstance(value, int): return value return super().to_representation(value) class JobRunSerializer(serializers.Serializer): def __init__(self, *args, **kwargs): ex = kwargs.pop('exporter') events = kwargs.pop('events', None) super().__init__(*args, **kwargs) if events is not None: self.fields["events"] = serializers.SlugRelatedField( queryset=events, required=True, allow_empty=False, slug_field='slug', many=True ) for k, v in ex.export_form_fields.items(): for m_from, m_to, m_kwargs in simple_mappings: if isinstance(v, m_from): self.fields[k] = m_to( required=v.required, allow_null=not v.required, validators=v.validators, **{kwarg: getattr(v, kwargs, None) for kwarg in m_kwargs} ) break if isinstance(v, forms.ModelMultipleChoiceField): self.fields[k] = PrimaryKeyRelatedField( queryset=v.queryset, required=v.required, allow_empty=not v.required, validators=v.validators, many=True ) elif isinstance(v, forms.ModelChoiceField): self.fields[k] = PrimaryKeyRelatedField( queryset=v.queryset, required=v.required, allow_null=not v.required, validators=v.validators, ) elif isinstance(v, forms.MultipleChoiceField): self.fields[k] = serializers.MultipleChoiceField( choices=v.choices, required=v.required, allow_empty=not v.required, validators=v.validators, ) elif isinstance(v, forms.ChoiceField): self.fields[k] = serializers.ChoiceField( choices=v.choices, required=v.required, allow_null=not v.required, validators=v.validators, ) else: self.fields[k] = FormFieldWrapperField(form_field=v, required=v.required, allow_null=not v.required) def to_internal_value(self, data): if isinstance(data, QueryDict): data = data.copy() for k, v in self.fields.items(): if isinstance(v, serializers.ManyRelatedField) and k not in data: data[k] = [] data = super().to_internal_value(data) return data