Ejemplo n.º 1
0
def _instance_overrides_method(base, instance, method_name):
    """
    Returns True if instance overrides a method (method_name)
    inherited from base.
    """
    bound_method = getattr(instance, method_name)
    unbound_method = getattr(base, method_name)
    return six.get_unbound_function(unbound_method) != six.get_method_function(bound_method)
    def get_customization_for_nested_field(self, field_name):
        """ Support of nested fields customization for:
         * EmbeddedDocumentField
         * NestedReference
         * Compound fields with EmbeddedDocument as a child:
            * ListField(EmbeddedDocument)/EmbeddedDocumentListField
            * MapField(EmbeddedDocument)

        Extracts fields, exclude, extra_kwargs and validate_*()
        attributes from parent serializer, related to attributes of field_name.
        """

        # This method is supposed to be called after self.get_fields(),
        # thus it assumes that fields and exclude are mutually exclusive
        # and at least one of them is set.
        #
        # Also, all the sanity checks are left up to nested field's
        # get_fields() method, so if something is wrong with customization
        # nested get_fields() will report this.

        fields = getattr(self.Meta, 'fields', None)
        exclude = getattr(self.Meta, 'exclude', None)

        if fields and fields != ALL_FIELDS and not isinstance(
                fields, (list, tuple)):
            raise TypeError(
                'The `fields` option must be a list or tuple or "__all__". '
                'Got %s.' % type(fields).__name__)

        if exclude and not isinstance(exclude, (list, tuple)):
            raise TypeError(
                'The `exclude` option must be a list or tuple. Got %s.' %
                type(exclude).__name__)

        assert not (fields and exclude), (
            "Cannot set both 'fields' and 'exclude' options on "
            "serializer {serializer_class}.".format(
                serializer_class=self.__class__.__name__))

        if fields is None and exclude is None:
            warnings.warn(
                "Creating a ModelSerializer without either the 'fields' "
                "attribute or the 'exclude' attribute is deprecated "
                "since 3.3.0. Add an explicit fields = '__all__' to the "
                "{serializer_class} serializer.".format(
                    serializer_class=self.__class__.__name__),
                DeprecationWarning)
            fields = ALL_FIELDS  # assume that fields are ALL_FIELDS

        # TODO: validators

        # get nested_fields or nested_exclude (supposed to be mutually exclusive, assign the other one to None)
        if fields:
            if fields == ALL_FIELDS:
                nested_fields = ALL_FIELDS
            else:
                nested_fields = [
                    field[len(field_name + '.'):] for field in fields
                    if field.startswith(field_name + '.')
                ]
            nested_exclude = None
        else:
            # leave all the sanity checks up to get_fields() method of nested field's serializer
            nested_fields = None
            nested_exclude = [
                field[len(field_name + '.'):] for field in exclude
                if field.startswith(field_name + '.')
            ]

        # get nested_extra_kwargs (including read-only fields)
        # TODO: uniqueness extra kwargs
        extra_kwargs = self.get_extra_kwargs()
        nested_extra_kwargs = {
            key[len(field_name + '.'):]: value
            for key, value in extra_kwargs.items()
            if key.startswith(field_name + '.')
        }

        # get nested_validate_methods dict {name: function}, rename e.g. 'validate_author__age()' -> 'validate_age()'
        # so that we can add them to nested serializer's definition under this new name
        # validate_methods are normally checked in rest_framework.Serializer.to_internal_value()
        nested_validate_methods = {}
        for attr in dir(self.__class__):
            if attr.startswith('validate_%s__' %
                               field_name.replace('.', '__')):
                method = get_unbound_function(getattr(self.__class__, attr))
                method_name = 'validate_' + attr[
                    len('validate_%s__' % field_name.replace('.', '__')):]
                nested_validate_methods[method_name] = method

        return Customization(nested_fields, nested_exclude,
                             nested_extra_kwargs, nested_validate_methods)
    def get_customization_for_nested_field(self, field_name):
        """ Support of nested fields customization for:
         * EmbeddedDocumentField
         * NestedReference
         * Compound fields with EmbeddedDocument as a child:
            * ListField(EmbeddedDocument)/EmbeddedDocumentListField
            * MapField(EmbeddedDocument)

        Extracts fields, exclude, extra_kwargs and validate_*()
        attributes from parent serializer, related to attributes of field_name.
        """

        # This method is supposed to be called after self.get_fields(),
        # thus it assumes that fields and exclude are mutually exclusive
        # and at least one of them is set.
        #
        # Also, all the sanity checks are left up to nested field's
        # get_fields() method, so if something is wrong with customization
        # nested get_fields() will report this.

        fields = getattr(self.Meta, 'fields', None)
        exclude = getattr(self.Meta, 'exclude', None)

        if fields and fields != ALL_FIELDS and not isinstance(fields, (list, tuple)):
            raise TypeError(
                'The `fields` option must be a list or tuple or "__all__". '
                'Got %s.' % type(fields).__name__
            )

        if exclude and not isinstance(exclude, (list, tuple)):
            raise TypeError(
                'The `exclude` option must be a list or tuple. Got %s.' %
                type(exclude).__name__
            )

        assert not (fields and exclude), (
            "Cannot set both 'fields' and 'exclude' options on "
            "serializer {serializer_class}.".format(
                serializer_class=self.__class__.__name__
            )
        )

        if fields is None and exclude is None:
            warnings.warn(
                "Creating a ModelSerializer without either the 'fields' "
                "attribute or the 'exclude' attribute is deprecated "
                "since 3.3.0. Add an explicit fields = '__all__' to the "
                "{serializer_class} serializer.".format(
                    serializer_class=self.__class__.__name__
                ),
                DeprecationWarning
            )
            fields = ALL_FIELDS  # assume that fields are ALL_FIELDS

        # TODO: validators

        # get nested_fields or nested_exclude (supposed to be mutually exclusive, assign the other one to None)
        if fields:
            if fields == ALL_FIELDS:
                nested_fields = ALL_FIELDS
            else:
                nested_fields = [field[len(field_name + '.'):] for field in fields if field.startswith(field_name + '.')]
            nested_exclude = None
        else:
            # leave all the sanity checks up to get_fields() method of nested field's serializer
            nested_fields = None
            nested_exclude = [field[len(field_name + '.'):] for field in exclude if field.startswith(field_name + '.')]

        # get nested_extra_kwargs (including read-only fields)
        # TODO: uniqueness extra kwargs
        extra_kwargs = self.get_extra_kwargs()
        nested_extra_kwargs = {key[len(field_name + '.'):]: value for key, value in extra_kwargs.items() if key.startswith(field_name + '.')}

        # get nested_validate_methods dict {name: function}, rename e.g. 'validate_author__age()' -> 'validate_age()'
        # so that we can add them to nested serializer's definition under this new name
        # validate_methods are normally checked in rest_framework.Serializer.to_internal_value()
        nested_validate_methods = {}
        for attr in dir(self.__class__):
            if attr.startswith('validate_%s__' % field_name.replace('.', '__')):
                method = get_unbound_function(getattr(self.__class__, attr))
                method_name = 'validate_' + attr[len('validate_%s__' % field_name.replace('.', '__')):]
                nested_validate_methods[method_name] = method

        return Customization(nested_fields, nested_exclude, nested_extra_kwargs, nested_validate_methods)