Пример #1
0
    def get_nested_field(self, model_field, related_model, to_many):
        class NestedModelSerializer(self._model_serializer_class):
            class Meta:
                model = related_model
                depth = self.opts.depth - 1

        if not self.opts.nestedFields:
            return NestedModelSerializer(many=to_many)

        fieldName = None
        if model_field:
            fieldName = model_field.name
        else:  # else means it is a reverse relationship so the accessor_name must be retrieved
            cls = self.opts.model
            opts = get_concrete_model(cls)._meta
            reverse_rels = opts.get_all_related_objects()
            reverse_rels += opts.get_all_related_many_to_many_objects()
            for relation in reverse_rels:
                accessorName = relation.get_accessor_name()
                if relation.model == related_model and accessorName in self.opts.nestedFields:
                    fieldName = accessorName
                    break

        customFields = self.opts.nestedFields.get(fieldName)
        if customFields is not None:
            class CustomFieldSerializer(self._model_serializer_class):
                class Meta:
                    model = related_model
                    fields = ['self'] + customFields[0] + list(customFields[1].keys())
                    nested_fields = customFields[1]
                    no_links = self.opts.noLinks
                    exclude = None

            return CustomFieldSerializer(many=to_many)
        return self.get_related_field(model_field, related_model, to_many)
    def get_default_fields(self):
        cls = self.opts.model
        opts = get_concrete_model(cls)
        fields = []
        fields += [getattr(opts, field) for field in cls._fields_ordered]

        ret = SortedDict()

        for model_field in fields:
            if isinstance(model_field, mongoengine.ObjectIdField):
                field = self.get_pk_field(model_field)
            else:
                field = self.get_field(model_field)

            if field:
                field.initialize(parent=self, field_name=model_field.name)
                ret[model_field.name] = field

        for field_name in self.opts.read_only_fields:
            assert field_name in ret,\
            "read_only_fields on '%s' included invalid item '%s'" %\
            (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
    def get_default_fields(self):
        cls = self.opts.model
        opts = get_concrete_model(cls)
        fields = []
        fields += [getattr(opts, field) for field in cls._fields_ordered]

        ret = SortedDict()

        for model_field in fields:
            if isinstance(model_field, mongoengine.ObjectIdField):
                field = self.get_pk_field(model_field)
            else:
                field = self.get_field(model_field)

            if field:
                field.initialize(parent=self, field_name=model_field.name)
                ret[model_field.name] = field

        for field_name in self.opts.read_only_fields:
            assert field_name in ret,\
            "read_only_fields on '%s' included invalid item '%s'" %\
            (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
Пример #4
0
    def get_nested_field(self, model_field, related_model, to_many):
        class NestedModelSerializer(self._model_serializer_class):
            class Meta:
                model = related_model
                depth = self.opts.depth - 1

        if not self.opts.nestedFields:
            return NestedModelSerializer(many=to_many)

        fieldName = None
        if model_field:
            fieldName = model_field.name
        else:  # else means it is a reverse relationship so the accessor_name must be retrieved
            cls = self.opts.model
            opts = get_concrete_model(cls)._meta
            reverse_rels = opts.get_all_related_objects()
            reverse_rels += opts.get_all_related_many_to_many_objects()
            for relation in reverse_rels:
                if relation.model == related_model:
                    fieldName = relation.get_accessor_name()

        customFields = self.opts.nestedFields.get(fieldName)
        if customFields is not None:

            class CustomFieldSerializer(self._model_serializer_class):
                class Meta:
                    model = related_model
                    fields = ['self'] + customFields[0] + list(
                        customFields[1].keys())
                    nested_fields = customFields[1]
                    exclude = None

            return CustomFieldSerializer(many=to_many)
        return self.get_related_field(model_field, related_model, to_many)
Пример #5
0
 def get_validation_exclusions(self):
     """
     Return a list of field names to exclude from model validation.
     """
     cls = self.opts.model
     opts = get_concrete_model(cls)._meta
     exclusions = [field.name for field in opts.fields + opts.many_to_many]
     for field_name, field in self.fields.items():
         if field_name in exclusions and not field.read_only:
             exclusions.remove(field_name)
     return exclusions
Пример #6
0
 def get_validation_exclusions(self):
     """
     Return a list of field names to exclude from model validation.
     """
     cls = self.opts.model
     opts = get_concrete_model(cls)._meta
     exclusions = [field.name for field in opts.fields + opts.many_to_many]
     for field_name, field in self.fields.items():
         if field_name in exclusions and not field.read_only:
             exclusions.remove(field_name)
     return exclusions
Пример #7
0
    def __init__(self, model, embedded_def_dict=None):
        super(EmbeddedObjectsField, self).__init__()
        self.model = model
        self.embedded_def_dict = embedded_def_dict

        self.opts = get_concrete_model(self.model)._meta
        self.related_fields = [field for field in self.opts.fields if field.serialize if field.rel]
        self.reverse_rels = self.opts.get_all_related_objects() + self.opts.get_all_related_many_to_many_objects()

        self.related_fields_names = [field.name for field in self.related_fields]
        self.reverse_rel_names = [relation.get_accessor_name() for relation in self.reverse_rels]
        self.possible_embedded_names = set(
            self.related_fields_names +
            self.reverse_rel_names +
            self.embedded_function_names() +
            self.embedded_property_names())
Пример #8
0
    def get_validation_exclusions(self, instance=None):
        """
        Return a list of field names to exclude from model validation.
        """
        cls = self.opts.model
        opts = get_concrete_model(cls)._meta
        exclusions = [field.name for field in opts.fields + opts.many_to_many]

        for field_name, field in self.fields.items():
            field_name = field.source or field_name
            if field_name in exclusions \
                and not field.read_only \
                and (field.required or hasattr(instance, field_name)) \
                and not isinstance(field, Serializer):
                exclusions.remove(field_name)
        return exclusions
Пример #9
0
    def get_validation_exclusions(self):
        """
        Return a list of field names to exclude from model validation.
        """
        cls = self.opts.model
        opts = get_concrete_model(cls)._meta
        exclusions = [field.name for field in opts.fields + opts.many_to_many]

        for field_name, field in self.fields.items():
            field_name = field.source or field_name
            if field_name in exclusions \
                and not field.read_only \
                and field.required \
                and not isinstance(field, Serializer):
                exclusions.remove(field_name)
        return exclusions
Пример #10
0
    def default_fields(self, nested=False):
        """
        Return all the fields that should be serialized for the model.
        """
        # TODO: Modify this so that it's called on init, and drop
        #       serialize/obj/data arguments.
        #
        #       We *could* provide a hook for dynamic fields, but
        #       it'd be nice if the default was to generate fields statically
        #       at the point of __init__

        cls = self.opts.model
        opts = get_concrete_model(cls)._meta
        pk_field = opts.pk
        while pk_field.rel:
            pk_field = pk_field.rel.to._meta.pk
        fields = [pk_field]
        fields += [field for field in opts.fields if field.serialize]
        fields += [field for field in opts.many_to_many if field.serialize]

        ret = SortedDict()
        is_pk = True  # First field in the list is the pk

        for model_field in fields:
            if is_pk:
                field = self.get_pk_field(model_field)
                is_pk = False
            elif model_field.rel and nested:
                field = self.get_nested_field(model_field)
            elif model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                field = self.get_related_field(model_field, to_many=to_many)
            else:
                field = self.get_field(model_field)

            if field:
                field.initialize(parent=self, field_name=model_field.name)
                ret[model_field.name] = field

        for field_name in self.opts.read_only_fields:
            assert field_name in ret, \
                "read_only_fields on '%s' included invalid item '%s'" % \
                (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
Пример #11
0
    def default_fields(self, nested=False):
        """
        Return all the fields that should be serialized for the model.
        """
        # TODO: Modfiy this so that it's called on init, and drop
        #       serialize/obj/data arguments.
        #
        #       We *could* provide a hook for dynamic fields, but
        #       it'd be nice if the default was to generate fields statically
        #       at the point of __init__

        cls = self.opts.model
        opts = get_concrete_model(cls)._meta
        pk_field = opts.pk
        while pk_field.rel:
            pk_field = pk_field.rel.to._meta.pk
        fields = [pk_field]
        fields += [field for field in opts.fields if field.serialize]
        fields += [field for field in opts.many_to_many if field.serialize]

        ret = SortedDict()
        is_pk = True  # First field in the list is the pk

        for model_field in fields:
            if is_pk:
                field = self.get_pk_field(model_field)
                is_pk = False
            elif model_field.rel and nested:
                field = self.get_nested_field(model_field)
            elif model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                field = self.get_related_field(model_field, to_many=to_many)
            else:
                field = self.get_field(model_field)

            if field:
                field.initialize(parent=self, field_name=model_field.name)
                ret[model_field.name] = field

        for field_name in self.opts.read_only_fields:
            assert field_name in ret, \
                "read_only_fields on '%s' included invalid item '%s'" % \
                (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
Пример #12
0
    def get_default_fields(self):
        """
        Return all the fields that should be serialized for the model.
        """

        cls = self.opts.model
        assert cls is not None, \
                "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__
        opts = get_concrete_model(cls)._meta
        pk_field = opts.pk

        # If model is a child via multitable inheritance, use parent's pk
        while pk_field.rel and pk_field.rel.parent_link:
            pk_field = pk_field.rel.to._meta.pk

        fields = [pk_field]
        fields += [field for field in opts.fields if field.serialize]
        fields += [field for field in opts.many_to_many if field.serialize]

        ret = SortedDict()
        nested = bool(self.opts.depth)
        is_pk = True  # First field in the list is the pk

        for model_field in fields:
            if is_pk:
                field = self.get_pk_field(model_field)
                is_pk = False
            elif model_field.rel and nested:
                field = self.get_nested_field(model_field)
            elif model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                field = self.get_related_field(model_field, to_many=to_many)
            else:
                field = self.get_field(model_field)

            if field:
                ret[model_field.name] = field

        for field_name in self.opts.read_only_fields:
            assert field_name in ret, \
                "read_only_fields on '%s' included invalid item '%s'" % \
                (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
Пример #13
0
    def get_default_fields(self):
        """
        Return all the fields that should be serialized for the model.
        """

        cls = self.opts.model
        assert cls is not None, \
                "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__
        opts = get_concrete_model(cls)._meta
        pk_field = opts.pk

        # If model is a child via multitable inheritance, use parent's pk
        while pk_field.rel and pk_field.rel.parent_link:
            pk_field = pk_field.rel.to._meta.pk

        fields = [pk_field]
        fields += [field for field in opts.fields if field.serialize]
        fields += [field for field in opts.many_to_many if field.serialize]

        ret = SortedDict()
        nested = bool(self.opts.depth)
        is_pk = True  # First field in the list is the pk

        for model_field in fields:
            if is_pk:
                field = self.get_pk_field(model_field)
                is_pk = False
            elif model_field.rel and nested:
                field = self.get_nested_field(model_field)
            elif model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                field = self.get_related_field(model_field, to_many=to_many)
            else:
                field = self.get_field(model_field)

            if field:
                ret[model_field.name] = field

        for field_name in self.opts.read_only_fields:
            assert field_name in ret, \
                "read_only_fields on '%s' included invalid item '%s'" % \
                (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
Пример #14
0
    def get_default_fields(self):
        """
        Return all the fields that should be serialized for the model.
        """

        cls = self.opts.model
        opts = get_concrete_model(cls)._meta
        pk_field = opts.pk
        while pk_field.rel:
            pk_field = pk_field.rel.to._meta.pk
        fields = [pk_field]
        fields += [field for field in opts.fields if field.serialize]
        fields += [field for field in opts.many_to_many if field.serialize]

        ret = SortedDict()
        nested = bool(self.opts.depth)
        is_pk = True  # First field in the list is the pk

        for model_field in fields:
            if is_pk:
                field = self.get_pk_field(model_field)
                is_pk = False
            elif model_field.rel and nested:
                field = self.get_nested_field(model_field)
            elif model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                field = self.get_related_field(model_field, to_many=to_many)
            else:
                field = self.get_field(model_field)

            if field:
                field.initialize(parent=self, field_name=model_field.name)
                ret[model_field.name] = field

        for field_name in self.opts.read_only_fields:
            assert field_name in ret, \
                "read_only_fields on '%s' included invalid item '%s'" % \
                (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
Пример #15
0
    def get_default_fields(self):
        """
        Return all the fields that should be serialized for the model.
        """

        cls = self.opts.model
        opts = get_concrete_model(cls)._meta
        pk_field = opts.pk
        while pk_field.rel:
            pk_field = pk_field.rel.to._meta.pk
        fields = [pk_field]
        fields += [field for field in opts.fields if field.serialize]
        fields += [field for field in opts.many_to_many if field.serialize]

        ret = SortedDict()
        nested = bool(self.opts.depth)
        is_pk = True  # First field in the list is the pk

        for model_field in fields:
            if is_pk:
                field = self.get_pk_field(model_field)
                is_pk = False
            elif model_field.rel and nested:
                field = self.get_nested_field(model_field)
            elif model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                field = self.get_related_field(model_field, to_many=to_many)
            else:
                field = self.get_field(model_field)

            if field:
                field.initialize(parent=self, field_name=model_field.name)
                ret[model_field.name] = field

        for field_name in self.opts.read_only_fields:
            assert field_name in ret, \
                "read_only_fields on '%s' included invalid item '%s'" % \
                (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
Пример #16
0
    def restore_fields(self, data, files):
        """
        Core of deserialization, together with `restore_object`.
        Converts a dictionary of data into a dictionary of deserialized fields.
        """
        reverted_data = {}
        copy_data = data.copy()

        if data is not None and not isinstance(data, dict):
            self._errors['non_field_errors'] = ['Invalid data']
            return None

        for field_name, field in self.fields.items():
            copy_data.pop(field_name, None)
            self.restore_initialize_field(field_name, field, data, files, reverted_data)

        # what's left of the data
        cls = self.opts.model
        assert cls is not None, \
            "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__
        opts = get_concrete_model(cls)._meta
        nested = bool(self.opts.depth)
        for field_name in copy_data.keys():
            try:
                model_field_tuple = opts.get_field_by_name(field_name)
                model_field = model_field_tuple[0]
            except models.FieldDoesNotExist:
                continue
            if model_field.rel:
                related_model = _resolve_model(model_field.rel.to)
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                if nested:
                    field = self.get_nested_field(model_field, related_model, to_many)
                else:
                    field = self.get_related_field(model_field, related_model, to_many)
                self.restore_initialize_field(field_name, field, data, files, reverted_data)

        return reverted_data
Пример #17
0
    def get_default_fields(self):
        """
        Overriding get_default_fields to do two things:
        2. Add suffix '_id' to all foreign keys
        """
        ret = super(AutoModelSerializer, self).get_default_fields()

        # Deal with forward relationships
        cls = self.opts.model
        opts = get_concrete_model(cls)._meta

        related_fields = [field for field in opts.fields if field.serialize if field.rel]

        # adding embedded fields for the foreign keys
        for model_field in related_fields:
            field_name = model_field.name

            del ret[field_name]
            to_many = isinstance(model_field, ManyToManyField)

            if not to_many:
                related_model = _resolve_model(model_field.rel.to)

                ret[field_name + '_id'] = self.get_related_field_with_source(model_field, related_model, to_many,
                                                                             source=field_name)

        # adding links field
        ret['_meta'] = MetaField()
        ret['_embedded'] = EmbeddedObjectsField(cls, embedded_def_dict=self.embedded_def_dict)



        # adding fields for properties
        for p_name, p_val in class_properties_with_attr(cls, 'field_class'):
            field_name = getattr(p_val, 'name', p_name) or p_name  # we use property name as field name by default
            ret[field_name] = p_val.field_class(source=p_name)

        return ret
Пример #18
0
    def get_default_fields(self):
        """
        Return all the fields that should be serialized for the model.
        """

        cls = self.opts.model
        assert cls is not None, \
                "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__
        opts = get_concrete_model(cls)._meta
        ret = SortedDict()
        nested = bool(self.opts.depth)

        # Deal with adding the primary key field
        pk_field = opts.pk
        while pk_field.rel and pk_field.rel.parent_link:
            # If model is a child via multitable inheritance, use parent's pk
            pk_field = pk_field.rel.to._meta.pk

        field = self.get_pk_field(pk_field)
        if field:
            ret[pk_field.name] = field

        # Deal with forward relationships
        forward_rels = [field for field in opts.fields if field.serialize]
        forward_rels += [field for field in opts.many_to_many if field.serialize]

        for model_field in forward_rels:
            if model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                related_model = model_field.rel.to

            if model_field.rel and nested:
                if len(inspect.getargspec(self.get_nested_field).args) == 2:
                    warnings.warn(
                        'The `get_nested_field(model_field)` call signature '
                        'is due to be deprecated. '
                        'Use `get_nested_field(model_field, related_model, '
                        'to_many) instead',
                        PendingDeprecationWarning
                    )
                    field = self.get_nested_field(model_field)
                else:
                    field = self.get_nested_field(model_field, related_model, to_many)
            elif model_field.rel:
                if len(inspect.getargspec(self.get_nested_field).args) == 3:
                    warnings.warn(
                        'The `get_related_field(model_field, to_many)` call '
                        'signature is due to be deprecated. '
                        'Use `get_related_field(model_field, related_model, '
                        'to_many) instead',
                        PendingDeprecationWarning
                    )
                    field = self.get_related_field(model_field, to_many=to_many)
                else:
                    field = self.get_related_field(model_field, related_model, to_many)
            else:
                field = self.get_field(model_field)

            if field:
                ret[model_field.name] = field

        # Deal with reverse relationships
        if not self.opts.fields:
            reverse_rels = []
        else:
            # Reverse relationships are only included if they are explicitly
            # present in the `fields` option on the serializer
            reverse_rels = opts.get_all_related_objects()
            reverse_rels += opts.get_all_related_many_to_many_objects()

        for relation in reverse_rels:
            accessor_name = relation.get_accessor_name()
            if not self.opts.fields or accessor_name not in self.opts.fields:
                continue
            related_model = relation.model
            to_many = relation.field.rel.multiple

            if nested:
                field = self.get_nested_field(None, related_model, to_many)
            else:
                field = self.get_related_field(None, related_model, to_many)

            if field:
                ret[accessor_name] = field

        # Add the `read_only` flag to any fields that have bee specified
        # in the `read_only_fields` option
        for field_name in self.opts.read_only_fields:
            assert field_name not in self.base_fields.keys(), \
                "field '%s' on serializer '%s' specfied in " \
                "`read_only_fields`, but also added " \
                "as an explict field.  Remove it from `read_only_fields`." % \
                (field_name, self.__class__.__name__)
            assert field_name in ret, \
                "Noexistant field '%s' specified in `read_only_fields` " \
                "on serializer '%s'." % \
                (self.__class__.__name__, field_name)
            ret[field_name].read_only = True

        return ret
Пример #19
0
    def get_default_fields(self):
        """
        Return all the fields that should be serialized for the model.
        """

        cls = self.opts.model
        assert cls is not None, \
                "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__
        opts = get_concrete_model(cls)._meta
        ret = SortedDict()
        nested = bool(self.opts.depth)

        # Deal with adding the primary key field
        pk_field = opts.pk
        while pk_field.rel and pk_field.rel.parent_link:
            # If model is a child via multitable inheritance, use parent's pk
            pk_field = pk_field.rel.to._meta.pk

        field = self.get_pk_field(pk_field)
        if field:
            ret[pk_field.name] = field

        # Deal with forward relationships
        forward_rels = [field for field in opts.fields if field.serialize]
        forward_rels += [field for field in opts.many_to_many if field.serialize]

        for model_field in forward_rels:
            has_through_model = False

            if model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                related_model = model_field.rel.to

                if to_many and not model_field.rel.through._meta.auto_created:
                    has_through_model = True

            if model_field.rel and nested:
                if len(inspect.getargspec(self.get_nested_field).args) == 2:
                    warnings.warn(
                        'The `get_nested_field(model_field)` call signature '
                        'is due to be deprecated. '
                        'Use `get_nested_field(model_field, related_model, '
                        'to_many) instead',
                        PendingDeprecationWarning
                    )
                    field = self.get_nested_field(model_field)
                else:
                    field = self.get_nested_field(model_field, related_model, to_many)
            elif model_field.rel:
                if len(inspect.getargspec(self.get_nested_field).args) == 3:
                    warnings.warn(
                        'The `get_related_field(model_field, to_many)` call '
                        'signature is due to be deprecated. '
                        'Use `get_related_field(model_field, related_model, '
                        'to_many) instead',
                        PendingDeprecationWarning
                    )
                    field = self.get_related_field(model_field, to_many=to_many)
                else:
                    field = self.get_related_field(model_field, related_model, to_many)
            else:
                field = self.get_field(model_field)

            if field:
                if has_through_model:
                    field.read_only = True

                ret[model_field.name] = field

        # Deal with reverse relationships
        if not self.opts.fields:
            reverse_rels = []
        else:
            # Reverse relationships are only included if they are explicitly
            # present in the `fields` option on the serializer
            reverse_rels = opts.get_all_related_objects()
            reverse_rels += opts.get_all_related_many_to_many_objects()

        for relation in reverse_rels:
            accessor_name = relation.get_accessor_name()
            if not self.opts.fields or accessor_name not in self.opts.fields:
                continue
            related_model = relation.model
            to_many = relation.field.rel.multiple
            has_through_model = False
            is_m2m = isinstance(relation.field,
                                models.fields.related.ManyToManyField)

            if is_m2m and not relation.field.rel.through._meta.auto_created:
                has_through_model = True

            if nested:
                field = self.get_nested_field(None, related_model, to_many)
            else:
                field = self.get_related_field(None, related_model, to_many)

            if field:
                if has_through_model:
                    field.read_only = True

                ret[accessor_name] = field

        # Add the `read_only` flag to any fields that have bee specified
        # in the `read_only_fields` option
        for field_name in self.opts.read_only_fields:
            assert field_name not in self.base_fields.keys(), \
                "field '%s' on serializer '%s' specified in " \
                "`read_only_fields`, but also added " \
                "as an explicit field.  Remove it from `read_only_fields`." % \
                (field_name, self.__class__.__name__)
            assert field_name in ret, \
                "Non-existant field '%s' specified in `read_only_fields` " \
                "on serializer '%s'." % \
                (field_name, self.__class__.__name__)
            ret[field_name].read_only = True

        return ret
Пример #20
0
    def get_default_fields(self, base_fields):
        """
        Return all the fields that should be serialized for the model.
        """

        cls = self.opts.model
        assert cls is not None, \
            "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__
        opts = get_concrete_model(cls)._meta
        ret = SortedDict()
        nested = bool(self.opts.depth)

        # Deal with adding the primary key field
        pk_field = opts.pk
        while pk_field.rel and pk_field.rel.parent_link:
            # If model is a child via multitable inheritance, use parent's pk
            pk_field = pk_field.rel.to._meta.pk

        field = self.get_pk_field(pk_field)
        if field:
            ret[pk_field.name] = field

        # Deal with forward relationships
        forward_rels = [field for field in opts.fields if field.serialize]
        forward_rels += [field for field in opts.many_to_many if field.serialize]

        for model_field in forward_rels:
            has_through_model = False

            if model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                related_model = _resolve_model(model_field.rel.to)

                if to_many and not model_field.rel.through._meta.auto_created:
                    has_through_model = True

            if model_field.rel and nested:
                self.add_field_to_embedded(model_field.name, self.get_nested_field(model_field, related_model, to_many))
            elif model_field.rel and model_field.name in base_fields:
                key = model_field.name
                field = base_fields[key]
                if isinstance(field, HyperlinkedRelatedField):
                    self.add_field_to_links(key, field)
                else:
                    self.add_field_to_embedded(key, field)
                ret[model_field.name] = field
            elif model_field.rel:
                field = self.get_related_field(model_field, related_model, to_many)
                if model_field.name not in self.additional_links:
                    self.add_field_to_links(model_field.name, field)
                ret[model_field.name] = field
            else:
                if model_field.name in self.additional_links:
                    # already been added to links
                    continue
                field = self.get_field(model_field)
                if field:
                    if has_through_model:
                        field.read_only = True

                    ret[model_field.name] = field

        # Deal with reverse relationships
        reverse_rels = opts.get_all_related_objects()
        reverse_rels += opts.get_all_related_many_to_many_objects()

        for relation in reverse_rels:
            accessor_name = relation.get_accessor_name()
            if accessor_name not in self.opts.fields and accessor_name not in base_fields:
                continue
            related_model = relation.model
            to_many = relation.field.rel.multiple
            has_through_model = False
            is_m2m = isinstance(relation.field,
                                models.fields.related.ManyToManyField)

            if (is_m2m and
                    hasattr(relation.field.rel, 'through') and
                    not relation.field.rel.through._meta.auto_created):
                has_through_model = True

            if nested:
                field = self.get_nested_field(None, related_model, to_many)
            elif accessor_name in base_fields:
                field = base_fields[accessor_name]
                base_fields.pop(accessor_name)
            else:
                field = self.get_related_field(None, related_model, to_many)

            if field:
                self.add_field_to_embedded(accessor_name, field, has_through_model)

        # Add the `read_only` flag to any fields that have bee specified
        # in the `read_only_fields` option
        for field_name in self.opts.read_only_fields:
            assert field_name not in self.base_fields.keys(), (
                "field '%s' on serializer '%s' specified in "
                "`read_only_fields`, but also added "
                "as an explicit field.  Remove it from `read_only_fields`." %
                (field_name, self.__class__.__name__))
            assert field_name in ret, (
                "Non-existant field '%s' specified in `read_only_fields` "
                "on serializer '%s'." %
                (field_name, self.__class__.__name__))
            ret[field_name].read_only = True

        for field_name in self.opts.write_only_fields:
            assert field_name not in self.base_fields.keys(), (
                "field '%s' on serializer '%s' specified in "
                "`write_only_fields`, but also added "
                "as an explicit field.  Remove it from `write_only_fields`." %
                (field_name, self.__class__.__name__))
            assert field_name in ret, (
                "Non-existant field '%s' specified in `write_only_fields` "
                "on serializer '%s'." %
                (field_name, self.__class__.__name__))
            ret[field_name].write_only = True

        return ret
Пример #21
0
    def get_default_fields(self):
        """
        Return all the fields that should be serialized for the model.
        """

        cls = self.opts.model
        assert cls is not None, \
                "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__
        opts = get_concrete_model(cls)._meta
        ret = SortedDict()
        nested = bool(self.opts.depth)

        # Deal with adding the primary key field
        pk_field = opts.pk
        while pk_field.rel and pk_field.rel.parent_link:
            # If model is a child via multitable inheritance, use parent's pk
            pk_field = pk_field.rel.to._meta.pk

        field = self.get_pk_field(pk_field)
        if field:
            ret[pk_field.name] = field

        # Deal with forward relationships
        forward_rels = [field for field in opts.fields if field.serialize]
        forward_rels += [field for field in opts.many_to_many if field.serialize]

        for model_field in forward_rels:
            has_through_model = False

            if model_field.rel:
                to_many = isinstance(model_field,
                                     models.fields.related.ManyToManyField)
                related_model = _resolve_model(model_field.rel.to)

                if to_many and not model_field.rel.through._meta.auto_created:
                    has_through_model = True

            if model_field.rel and nested:
                if len(inspect.getargspec(self.get_nested_field).args) == 2:
                    warnings.warn(
                        'The `get_nested_field(model_field)` call signature '
                        'is due to be deprecated. '
                        'Use `get_nested_field(model_field, related_model, '
                        'to_many) instead',
                        PendingDeprecationWarning
                    )
                    field = self.get_nested_field(model_field)
                else:
                    field = self.get_nested_field(model_field, related_model, to_many)
            elif model_field.rel:
                if len(inspect.getargspec(self.get_nested_field).args) == 3:
                    warnings.warn(
                        'The `get_related_field(model_field, to_many)` call '
                        'signature is due to be deprecated. '
                        'Use `get_related_field(model_field, related_model, '
                        'to_many) instead',
                        PendingDeprecationWarning
                    )
                    field = self.get_related_field(model_field, to_many=to_many)
                else:
                    field = self.get_related_field(model_field, related_model, to_many)
            else:
                field = self.get_field(model_field)

            if field:
                if has_through_model:
                    field.read_only = True

                ret[model_field.name] = field

        # Deal with reverse relationships
        if not self.opts.fields:
            reverse_rels = []
        else:
            # Reverse relationships are only included if they are explicitly
            # present in the `fields` option on the serializer
            reverse_rels = opts.get_all_related_objects()
            reverse_rels += opts.get_all_related_many_to_many_objects()

        for relation in reverse_rels:
            accessor_name = relation.get_accessor_name()
            if not self.opts.fields or accessor_name not in self.opts.fields:
                continue
            related_model = relation.model
            to_many = relation.field.rel.multiple
            has_through_model = False
            is_m2m = isinstance(relation.field,
                                models.fields.related.ManyToManyField)

            if (is_m2m and
                hasattr(relation.field.rel, 'through') and
                not relation.field.rel.through._meta.auto_created):
                has_through_model = True

            if nested:
                field = self.get_nested_field(None, related_model, to_many)
            else:
                field = self.get_related_field(None, related_model, to_many)

            if field:
                if has_through_model:
                    field.read_only = True

                ret[accessor_name] = field

        # Ensure that 'read_only_fields' is an iterable
        assert isinstance(self.opts.read_only_fields, (list, tuple)), '`read_only_fields` must be a list or tuple'

        # Add the `read_only` flag to any fields that have been specified
        # in the `read_only_fields` option
        for field_name in self.opts.read_only_fields:
            assert field_name not in self.base_fields.keys(), (
                "field '%s' on serializer '%s' specified in "
                "`read_only_fields`, but also added "
                "as an explicit field.  Remove it from `read_only_fields`." %
                (field_name, self.__class__.__name__))
            assert field_name in ret, (
                "Non-existant field '%s' specified in `read_only_fields` "
                "on serializer '%s'." %
                (field_name, self.__class__.__name__))
            ret[field_name].read_only = True

        # Ensure that 'write_only_fields' is an iterable
        assert isinstance(self.opts.write_only_fields, (list, tuple)), '`write_only_fields` must be a list or tuple'

        for field_name in self.opts.write_only_fields:
            assert field_name not in self.base_fields.keys(), (
                "field '%s' on serializer '%s' specified in "
                "`write_only_fields`, but also added "
                "as an explicit field.  Remove it from `write_only_fields`." %
                (field_name, self.__class__.__name__))
            assert field_name in ret, (
                "Non-existant field '%s' specified in `write_only_fields` "
                "on serializer '%s'." %
                (field_name, self.__class__.__name__))
            ret[field_name].write_only = True

        for field_name, field in ret.items():
            if not getattr(field, '_name', None):
                field.set_name(field_name)

        return ret