def dehydrate(self, bundle):
        assert bundle.obj

        the_m2ms = None

        if isinstance(self.attribute, basestring):
            the_m2ms = getattr(bundle.obj, self.attribute)
        elif callable(self.attribute):
            the_m2ms = self.attribute(bundle)

        if not the_m2ms:
            if not self.null:
                raise exceptions.ApiFieldError(
                    "The document %r has an empty attribute '%s' and does not allow a null value."
                    % (bundle.obj, self.attribute))
            return []

        self.m2m_resources = []
        m2m_dehydrated = []

        for index, m2m in enumerate(the_m2ms):
            m2m.pk = index
            m2m.parent = bundle.obj
            m2m_resource = self.get_related_resource(m2m)
            m2m_bundle = tastypie_bundle.Bundle(obj=m2m,
                                                request=bundle.request)
            self.m2m_resources.append(m2m_resource)
            m2m_dehydrated.append(
                self.dehydrate_related(m2m_bundle, m2m_resource))

        return m2m_dehydrated
Beispiel #2
0
    def dehydrate(self, bundle, for_list=True):
        the_m2ms = None

        if isinstance(self.attribute, basestring):
            the_m2ms = getattr(bundle.obj, self.attribute)
        elif callable(self.attribute):
            the_m2ms = self.attribute(bundle)

        if not the_m2ms:
            if not self.null:
                raise exceptions.ApiFieldError(
                    "The document %r has an empty attribute '%s' and does not allow a null value."
                    % (bundle.obj, self.attribute))
            return []

        self.m2m_resources = []
        m2m_dehydrated = []

        # the_m2ms is a list, not a queryset
        for m2m in the_m2ms:
            m2m_resource = self.get_related_resource(m2m)
            m2m_bundle = tastypie_bundle.Bundle(obj=m2m,
                                                request=bundle.request)
            self.m2m_resources.append(m2m_resource)
            m2m_dehydrated.append(
                self.dehydrate_related(m2m_bundle,
                                       m2m_resource,
                                       for_list=for_list))

        return m2m_dehydrated
    def full_hydrate(self, bundle):
        # When updating objects, we want to force only updates of the same type, and object
        # should be completely replaced if type is changed, so we throw and exception here
        # to direct program logic flow (it is cached and replace instead of update is tried)
        if bundle.obj and self._meta.object_class is not bundle.obj.__class__:
            raise tastypie_exceptions.NotFound(
                "A document instance matching the provided arguments could not be found."
            )

        bundle = super(MongoEngineResource, self).full_hydrate(bundle)

        # We redo check for required fields as Tastypie is not
        # reliable as it does checks in an inconsistent way
        # (https://github.com/toastdriven/django-tastypie/issues/491)
        for field_object in self.fields.itervalues():
            if field_object.readonly or getattr(field_object, '_primary_key',
                                                False):
                continue

            if not field_object.attribute:
                continue

            # Tastypie also skips setting value if it is None, but this means
            # updates to None are ignored: this is not good as it hides invalid
            # PUT/PATCH REST requests (setting value to None which should fail
            # validation (field required) is simply ignored and value is left
            # as it is)
            # (https://github.com/toastdriven/django-tastypie/issues/492)
            # We hydrate field again only if existing value is not None
            if getattr(bundle.obj, field_object.attribute, None) is not None:
                value = NOT_HYDRATED

                # Tastypie also ignores missing fields in PUT,
                # so we check for missing field here
                # (https://github.com/toastdriven/django-tastypie/issues/496)
                if field_object.instance_name not in bundle.data:
                    if field_object.has_default():
                        if callable(field_object.default):
                            value = field_object.default()
                        else:
                            value = field_object.default
                    else:
                        value = None
                else:
                    value = field_object.hydrate(bundle)
                if value is None:
                    setattr(bundle.obj, field_object.attribute, None)

            if field_object.blank or field_object.null:
                continue

            # We are just trying to fix Tastypie here, for other "null" values
            # like [] and {} we leave to MongoEngine validate to catch them
            if getattr(bundle.obj, field_object.attribute, None) is None:
                raise tastypie_exceptions.ApiFieldError(
                    "The '%s' field has no data and doesn't allow a default or null value."
                    % field_object.instance_name)

        return bundle
    def dehydrate(self, bundle, for_list=True):
        if not bundle.obj or not bundle.obj.pk:
            if not self.null:
                raise exceptions.ApiFieldError(
                    "The document %r does not have a primary key and can not be used in a ReferencedList context."
                    % bundle.obj)

            return []

        the_m2ms = None

        if isinstance(self.attribute, basestring):
            the_m2ms = getattr(bundle.obj, self.attribute)
        elif callable(self.attribute):
            the_m2ms = self.attribute(bundle)

        if not the_m2ms:
            if not self.null:
                raise exceptions.ApiFieldError(
                    "The document %r has an empty attribute '%s' and does not allow a null value."
                    % (bundle.obj, self.attribute))
            return []

        self.m2m_resources = []
        m2m_dehydrated = []

        # the_m2ms is a list, not a queryset
        for m2m in the_m2ms:
            m2m_resource = self.get_related_resource(m2m)
            m2m_bundle = tastypie_bundle.Bundle(obj=m2m,
                                                request=bundle.request)
            self.m2m_resources.append(m2m_resource)
            if tastypie.__version__ >= (0, 9, 15):
                m2m_dehydrated.append(
                    self.dehydrate_related(m2m_bundle,
                                           m2m_resource,
                                           for_list=for_list))
            else:
                m2m_dehydrated.append(
                    self.dehydrate_related(m2m_bundle, m2m_resource))

        return m2m_dehydrated
 def build_related_resource(self, value, **kwargs):
     # A version of build_related_resource which allows only dictionary-like data
     if hasattr(value, 'items'):
         self.fk_resource = self.to_class(self.get_api_name())
         # We force resource to cannot be updated so that
         # it is just constructed by resource_from_data
         self.fk_resource.can_update = lambda: False
         return self.resource_from_data(self.fk_resource, value, **kwargs)
     # Or if related object already exists (this happens with PATCH request)
     elif getattr(value, 'obj', None):
         return value
     else:
         raise exceptions.ApiFieldError(
             "The '%s' field was not given a dictionary-alike data: %s." %
             (self.instance_name, value))
    def dehydrate(self, bundle, for_list=True):
        assert bundle.obj

        the_m2ms = None

        if isinstance(self.attribute, basestring):
            the_m2ms = getattr(bundle.obj, self.attribute)
        elif callable(self.attribute):
            the_m2ms = self.attribute(bundle)

        if not the_m2ms:
            if not self.null:
                raise exceptions.ApiFieldError(
                    "The document %r has an empty attribute '%s' and does not allow a null value."
                    % (bundle.obj, self.attribute))
            return []

        self.m2m_resources = []
        m2m_dehydrated = []

        # the_m2ms is a list, not a queryset
        for index, m2m in enumerate(the_m2ms):
            m2m.parent = bundle.obj
            m2m_resource = self.get_related_resource(m2m)

            pk_field = getattr(m2m_resource._meta, 'id_field', None)
            if pk_field is None:
                m2m.pk = index
            else:
                m2m.__class__.pk = link_property(pk_field)

            m2m_bundle = tastypie_bundle.Bundle(obj=m2m,
                                                request=bundle.request)
            self.m2m_resources.append(m2m_resource)
            if tastypie.__version__ >= (0, 9, 15):
                m2m_dehydrated.append(
                    self.dehydrate_related(m2m_bundle,
                                           m2m_resource,
                                           for_list=for_list))
            else:
                m2m_dehydrated.append(
                    self.dehydrate_related(m2m_bundle, m2m_resource))

        return m2m_dehydrated
    def full_hydrate(self, bundle):
        # When updating objects, we want to force only updates of the same type, and object
        # should be completely replaced if type is changed, so we throw and exception here
        # to direct program logic flow (it is cached and replace instead of update is tried)
        if bundle.obj and self._meta.object_class is not bundle.obj.__class__:
            raise tastypie_exceptions.NotFound(
                "A document instance matching the provided arguments could not be found."
            )

        bundle = super(MongoEngineResource, self).full_hydrate(bundle)

        # We redo check for required fields as Tastypie is not
        # reliable as it does checks in an inconsistent way
        # (https://github.com/toastdriven/django-tastypie/issues/491)
        for field_object in self.fields.itervalues():
            if field_object.readonly:
                continue

            if not field_object.attribute:
                continue

            value = NOT_HYDRATED

            # Tastypie also skips setting value if it is None, but this means
            # updates to None are ignored: this is not good as it hides invalid
            # PUT/PATCH REST requests (setting value to None which should fail
            # validation (field required) is simply ignored and value is left
            # as it is)
            # (https://github.com/toastdriven/django-tastypie/issues/492)
            # We hydrate field again only if existing value is not None
            if getattr(bundle.obj, field_object.attribute, None) is not None:
                # Tastypie also ignores missing fields in PUT,
                # so we check for missing field here
                # (https://github.com/toastdriven/django-tastypie/issues/496)
                if field_object.instance_name not in bundle.data:
                    if field_object._default is not tastypie_fields.NOT_PROVIDED:
                        if callable(field_object.default):
                            value = field_object.default()
                        else:
                            value = field_object.default
                    else:
                        value = None
                else:
                    value = field_object.hydrate(bundle)
                if value is None:
                    # This does not really set None in a way that calling
                    # getattr on bundle.obj would return None later on
                    # This is how MongoEngine is implemented
                    # (https://github.com/hmarr/mongoengine/issues/505)
                    setattr(bundle.obj, field_object.attribute, None)

            if field_object.blank or field_object.null:
                continue

            # We are just trying to fix Tastypie here, for other "null" values
            # like [] and {} we leave to validate bellow to catch them
            if getattr(
                    bundle.obj, field_object.attribute, None
            ) is None or value is None:  # We also have to check value, read comment above
                raise tastypie_exceptions.ApiFieldError(
                    "The '%s' field has no data and doesn't allow a default or null value."
                    % field_object.instance_name)

        # We validate MongoEngine object here so that possible exception
        # is thrown before going to MongoEngine layer, wrapped in
        # Django exception so that it is handled properly
        # is_valid method is too early as bundle.obj is not yet ready then
        try:
            # Validation fails for unsaved related resources, so
            # we fake pk here temporary, for validation code to
            # assume resource is saved
            pk = getattr(bundle.obj, 'pk', None)
            try:
                if pk is None:
                    bundle.obj.pk = bson.ObjectId()
                bundle.obj.validate()
            finally:
                if pk is None:
                    bundle.obj.pk = pk
        except mongoengine.ValidationError, e:
            raise exceptions.ValidationError(e.message)