'''
Haul uses DRF ``ModelSerializer`` as a base for its serialization.
This means you can use custom ``Field`` and ``Serializer`` objects to serialize and deserialize fields.
'''
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from .policy import ExportPolicy
from .types import ID, Ref
[docs]class DummyField(serializers.Field):
def __init__(self, *args, **kwargs):
super().__init__(*args, read_only=True, allow_null=True, required=False)
[docs] def run_validation(self, data=None):
return None
[docs] def get_attribute(self, instance):
return None
[docs] def to_representation(self, value):
return None
[docs] def to_internal_value(self, data):
return None
[docs]class ForeignKey(serializers.Field):
export_policy: ExportPolicy
def __init__(self, *args, queryset=None, many=False, **kwargs):
super().__init__(*args, read_only=False, **kwargs)
self._many = many
[docs] def bind(self, field_name, parent):
super().bind(field_name, parent)
self.export_policy = self.context.get('export_policy')
[docs] def get_attribute(self, instance):
return getattr(instance, self.source)
[docs] def to_representation(self, value):
if self._many:
return [
ID.from_object(instance)
for instance in value
if self.export_policy.should_export_object(instance)
]
return ID.from_object(value) if self.export_policy.should_export_object(value) else None
[docs] def to_internal_value(self, data):
if self._many:
return Ref(ids=data, field=self.source, nullable=self.allow_null)
else:
return Ref(ids=[data], field=self.source, nullable=self.allow_null)
class _BaseM2X(serializers.Field):
weak = False
export_policy: ExportPolicy
def bind(self, field_name, parent):
super().bind(field_name, parent)
self.export_policy = self.context.get('export_policy')
def get_attribute(self, instance):
return getattr(instance, self.source).all()
def to_representation(self, value):
return [
ID.from_object(instance)
for instance in value
if self.export_policy.should_export_object(instance)
]
def to_internal_value(self, data):
return Ref(data, field=self.source, nullable=True, weak=self.weak)
[docs]class ManyToMany(_BaseM2X):
weak = False
[docs]class ReverseForeignKey(_BaseM2X):
weak = True
def __init__(self, *args, **kwargs):
super().__init__(*args, allow_null=True)
[docs]class Exporter(serializers.ModelSerializer):
serializer_related_field = DummyField
[docs] def build_standard_field(self, field_name, model_field):
cls, kwargs = super().build_standard_field(field_name, model_field)
if 'validators' in kwargs:
kwargs['validators'] = [x for x in kwargs['validators'] if not isinstance(x, UniqueValidator)]
kwargs.pop('read_only', None)
kwargs['required'] = False
return cls, kwargs