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)