def dehydrate(self, bundle, for_list=True): if not bundle.obj or not bundle.obj.pk: if not self.null: raise ApiFieldError( "The model '%r' does not have a primary key and can not " "be used in a ToMany 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 ApiFieldError( "The model '%r' has an empty attribute '%s' and doesn't " "allow a null value." % (bundle.obj, self.attribute), ) return [] self.m2m_resources = [] m2m_dehydrated = [] for m2m in the_m2ms.filter(*self.filter_args_func(), **self.filter_kwargs_func()): m2m_resource = self.get_related_resource(m2m) m2m_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), ) return m2m_dehydrated
def build_related_resource(self, value): """ Used to ``hydrate`` the data provided. If just a URL is provided, the related resource is attempted to be loaded. If a dictionary-like structure is provided, a fresh resource is created. """ self.fk_resource = self.to_class() if isinstance(value, basestring): # We got a URI. Load the object and assign it. try: obj = self.fk_resource.get_via_uri(value) return self.fk_resource.full_dehydrate(obj) except ObjectDoesNotExist: raise ApiFieldError("Could not find the provided object via resource URI '%s'." % value) elif hasattr(value, 'items'): # Try to hydrate the data provided. value = dict_strip_unicode_keys(value) self.fk_bundle = Bundle(data=value) try: return self.fk_resource.obj_update(self.fk_bundle, **value) except NotFound: try: # Attempt lookup by primary key lookup_kwargs = dict((k, v) for k, v in value.iteritems() if getattr(self.fk_resource, k).unique) if not lookup_kwargs: raise NotFound return self.fk_resource.obj_update(self.fk_bundle, **lookup_kwargs) except NotFound: return self.fk_resource.full_hydrate(self.fk_bundle) except MultipleObjectsReturned: return self.fk_resource.full_hydrate(self.fk_bundle) else: raise ApiFieldError("The '%s' field has was given data that was not a URI and not a dictionary-alike: %s." % (self.instance_name, value))
def dehydrate(self, bundle, for_list=True): foreign_obj = None if callable(self.attribute): previous_obj = bundle.obj foreign_obj = self.attribute(bundle) elif isinstance(self.attribute, six.string_types): foreign_obj = bundle.obj for attr in self._attrs: previous_obj = foreign_obj try: foreign_obj = getattr(foreign_obj, attr, None) except ObjectDoesNotExist: foreign_obj = None if not foreign_obj: if not self.null: if callable(self.attribute): raise ApiFieldError(u"The related resource for resource %s could not be found." % (previous_obj)) else: raise ApiFieldError(u"The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr)) return None fk_resource = self.get_related_resource(foreign_obj) # Up to this point we've copied the code from tastypie 0.13.1. Now # we add caching. cache_key = fk_resource.generate_cache_key('related', pk=foreign_obj.pk, for_list=for_list, ) dehydrated = fk_resource._meta.cache.get(cache_key) if dehydrated is None: fk_bundle = Bundle(obj=foreign_obj, request=bundle.request) dehydrated = self.dehydrate_related(fk_bundle, fk_resource, for_list=for_list) fk_resource._meta.cache.set(cache_key, dehydrated) return dehydrated
def dehydrate(self, bundle, for_list=True): foreign_obj = None if callable(self.attribute): previous_obj = bundle.obj foreign_obj = self.attribute(bundle) elif isinstance(self.attribute, six.string_types): foreign_obj = bundle.obj for attr in self._attrs: previous_obj = foreign_obj try: foreign_obj = getattr(foreign_obj, attr, None) except ObjectDoesNotExist: foreign_obj = None if not foreign_obj: if not self.null: if callable(self.attribute): raise ApiFieldError("The related resource for resource %s could not be found." % (previous_obj)) else: raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr)) return None fk_resource = self.get_related_resource(foreign_obj) fk_bundle = Bundle(obj=foreign_obj, request=bundle.request) return self.dehydrate_related(fk_bundle, fk_resource, for_list=for_list)
def dehydrate(self, bundle): if not bundle.obj or not bundle.obj.pk: if not self.null: raise ApiFieldError("The model '%r' does not have a primary key and can not be used in a ToMany context." % bundle.obj) return [] if not getattr(bundle.obj, self.attribute): if not self.null: raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (bundle.obj, self.attribute)) return [] self.m2m_resources = [] m2m_dehydrated = [] # TODO: Also model-specific and leaky. Relies on there being a # ``Manager`` there. for m2m in getattr(bundle.obj, self.attribute).all(): m2m_resource = self.get_related_resource(m2m) m2m_bundle = Bundle(obj=m2m) self.m2m_resources.append(m2m_resource) m2m_dehydrated.append(self.dehydrate_related(m2m_bundle, m2m_resource)) return m2m_dehydrated
def resource_from_uri(self, fk_resource, uri, request=None, related_obj=None, related_name=None): """ Given a URI is provided, the related resource is attempted to be loaded based on the identifiers in the URI. """ err_msg = "Could not find the provided %s object via resource URI '%s'." % ( fk_resource._meta.resource_name, uri, ) if not uri: raise ApiFieldError(err_msg) try: obj = fk_resource.get_via_uri(uri, request=request) bundle = fk_resource.build_bundle(obj=obj, request=request, via_uri=True) return fk_resource.full_dehydrate(bundle) except ObjectDoesNotExist: raise ApiFieldError(err_msg)
def dehydrate(self, bundle): if not bundle.obj or not bundle.obj.pk: if not self.null: raise ApiFieldError("The model '%r' does not have a primary \ key and can not be used in a ToMany context." % bundle.obj) return [] the_m2ms = None previous_obj = bundle.obj attr = self.attribute if isinstance(self.attribute, basestring): attrs = self.attribute.split('__') the_m2ms = bundle.obj for attr in attrs: previous_obj = the_m2ms try: the_m2ms = getattr(the_m2ms, attr, None) the_m2ms = self.apply_m2m_filters(bundle.request, attr, the_m2ms.all()) except ObjectDoesNotExist: the_m2ms = None if not the_m2ms: break try: the_m2ms = self.apply_sorting(bundle.request, the_m2ms.all()) except InvalidSortError: pass elif callable(self.attribute): the_m2ms = self.attribute(bundle) if not the_m2ms: if not self.null: raise ApiFieldError("The model '%r' has an empty attribute \ '%s' and doesn't allow a null value." % (previous_obj, attr)) return [] self.m2m_resources = [] m2m_dehydrated = [] # TODO: Also model-specific and leaky. Relies on there being a # ``Manager`` there. for m2m in the_m2ms.select_related(): m2m_resource = self.get_related_resource(m2m) m2m_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
def dehydrate(self, bundle, for_list=True): if not bundle.obj or not bundle.obj.pk: if not self.null: raise ApiFieldError( "The model '%r' does not have a primary key and can not be used in a ToMany context." % bundle.obj) return [] the_m2ms = None previous_obj = bundle.obj attr = self.attribute if isinstance(self.attribute, six.string_types): attrs = self.attribute.split('__') the_m2ms = bundle.obj for attr in attrs: previous_obj = the_m2ms try: the_m2ms = getattr(the_m2ms, attr, None) except ObjectDoesNotExist: the_m2ms = None if not the_m2ms: break elif callable(self.attribute): the_m2ms = self.attribute(bundle) if not the_m2ms: if not self.null: raise ApiFieldError( "The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr)) return [] self.m2m_resources = [] m2m_dehydrated = [] # TODO: Also model-specific and leaky. Relies on there being a # ``Manager`` there. the_m2ms_list = the_m2ms.all() if self.filter: the_m2ms_list = the_m2ms_list.filter(**filter) if self.limit: the_m2ms_list = the_m2ms_list[0:self.limit] for m2m in the_m2ms_list: m2m_resource = self.get_related_resource(m2m) m2m_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 hydrate(self, bundle): """ Takes data stored in the bundle for the field and returns it. Used for taking simple data and building a instance object. """ if self.readonly: return None if not bundle.data.has_key(self.instance_name): is_related = getattr(self, 'is_related', False) is_m2m = getattr(self, 'is_m2m', False) if is_related and not is_m2m: # We've got an FK (or alike field) & a possible parent object. # Check for it. if bundle.related_obj and bundle.related_name in ( self.attribute, self.instance_name): return bundle.related_obj # Functor for safely checking if bundle.obj has a non-None property def has_non_null_attr(obj, name): try: return getattr(obj, name, None) is not None except: if is_related: return None else: raise if self.blank: return None elif self.attribute and has_non_null_attr(bundle.obj, self.attribute): return getattr(bundle.obj, self.attribute) elif self.instance_name and has_non_null_attr( bundle.obj, self.instance_name): return getattr(bundle.obj, self.instance_name) elif self.has_default(): if callable(self._default): return self._default() return self._default elif self.null: return None else: raise ApiFieldError( "The '%s' field has no data and doesn't allow a default or null value." % self.instance_name) bundle_val = bundle.data[self.instance_name] if bundle_val is None and not self.null: raise ApiFieldError("The '%s' field doesn't allow a null value." % self.instance_name) else: return bundle_val
def hydrate_recipient(self, bundle): recipient = bundle.data['recipient'] try: if bundle.request.user.username == recipient: raise ApiFieldError("不能邀请自己") user = User.objects.get_by_natural_key(recipient) bundle.data['recipient'] = user except ObjectDoesNotExist: raise ApiFieldError("用户不存在") return bundle
def hydrate_license(self, bundle): if "license" not in bundle.data: raise ApiFieldError("You must set a license for your picture") try: license = License.objects.get(id=bundle.data["license"]) except: raise ApiFieldError("The selected license is incorrect") bundle.obj.license = license return bundle
def hydrate(self, bundle): value = super(DateTimeField, self).hydrate(bundle) if value and not hasattr(value, 'year'): if isinstance(value, six.string_types): try: # Try to rip a date/datetime out of it. value = make_aware(parse(value)) except (ValueError, TypeError): raise ApiFieldError("Datetime provided to '%s' field doesn't appear to be a valid datetime string: '%s'" % (self.instance_name, value)) else: raise ApiFieldError("Datetime provided to '%s' field must be a string: %s" % (self.instance_name, value)) return value
def dehydrate(self, bundle, **kwargs): """ This modified field, allow to include resource_uri of related resources without doing another database query. Using select_related() in resource.meta.queryset also avoids doing extra queries for each object, can be used instead of this class """ if not self.full: pk = getattr(bundle.obj, self.attribute + "_id", None) if not pk: if not self.null: raise ApiFieldError( """The model '%r' has an empty attribute '%s' and doesn't allow a null value.""" % (bundle.obj, self.attribute)) return None # just create a temporal object with only PK temporal_class = type('TemporalModel', (object,), {'pk': pk}) temporal_obj = temporal_class() # from this point, is almost the same stuff that tastypie does. self.fk_resource = self.get_related_resource(temporal_obj) fk_bundle = Bundle( obj=temporal_obj, request=bundle.request) return self.dehydrate_related(fk_bundle, self.fk_resource) return super(OptimizedToOneField, self).dehydrate(bundle, **kwargs)
def to_time(self, s): try: dt = parse(s) except (ValueError, TypeError) as e: raise ApiFieldError(str(e)) else: return datetime.time(dt.hour, dt.minute, dt.second, dt.microsecond)
def dehydrate(self, bundle, **kwargs): """ If field is configured to only return the resource URI (full=False), a temporal object will be created with only the PK available, this key will be filled with the value saved at self.attribute_id In case, field's self.full is set to True, original dehydrate process will be used. """ if not self.full: pk = getattr(bundle.obj, self.attribute + "_id", None) if not pk: if not self.null: raise ApiFieldError( """The model '%r' has an empty attribute '%s' and doesn't allow a null value.""" % (bundle.obj, self.attribute)) return None # just create a temporal object with only PK temporal_obj = type('TemporalModel', (object,), {'pk': pk})() # from this point, is almost the same stuff that tastypie does. self.fk_resource = self.get_related_resource(temporal_obj) fk_bundle = Bundle( obj=temporal_obj, request=bundle.request) return self.dehydrate_related(fk_bundle, self.fk_resource) return super(OptimizedToOneField, self).dehydrate(bundle, **kwargs)
def __init__(self, *args, **kwargs): super(ChildResource, self).__init__(*args, **kwargs) # Set the parent resource and name self.parent_field_name = self._meta.parent self.parent_resource = None for field, field_type in self.fields.iteritems(): if field == self.parent_field_name and isinstance( field_type, RelatedField): self.parent_resource = field_type.to if self.parent_resource is None: raise ApiFieldError("Could not find parent resource: %s" % self._meta.parent) self.parent_resource_instance = self.parent_resource( ) # cache an instance of the parent resource # Add filtering for the parent filters_for_parent = self._meta.filtering.setdefault( self.parent_field_name, []) if filters_for_parent not in ( ALL, ALL_WITH_RELATIONS) and "exact" not in filters_for_parent: if isinstance(filters_for_parent, list): filters_for_parent.append("exact") elif isinstance(filters_for_parent, tuple): filters_for_parent = list(filters_for_parent) filters_for_parent.append("exact") self._meta.filtering[self.parent_field_name] = tuple( filters_for_parent)
def resource_from_uri(self, fk_resource, uri, request=None, related_obj=None, related_name=None): try: obj = fk_resource.get_via_uri(uri, request=request) fk_resource = self.get_related_resource(obj) return super(GenericForeignKeyField, self).resource_from_uri(fk_resource, uri, request, related_obj, related_name) except ObjectDoesNotExist: raise ApiFieldError("Could not find the provided object via resource URI '%s'." % uri)
def hydrate_m2m(self, bundle): if self.readonly: return None if bundle.data.get(self.instance_name) is None: if self.blank: return [] if self.null: return [] raise ApiFieldError( "The '%s' field has no data and doesn't allow a null value." % self.instance_name) kwargs = { 'request': bundle.request, } if self.related_name: kwargs['related_obj'] = bundle.obj kwargs['related_name'] = self.related_name return [ self.build_related_resource(value, **kwargs) for value in bundle.data.get(self.instance_name) if value is not None ]
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 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_key, m2m_obj in the_m2ms.iteritems(): m2m_resource = self.get_related_resource(m2m_obj) m2m_bundle = tastypie_bundle.Bundle(obj=m2m_obj, request=bundle.request) self.m2m_resources[m2m_key] = m2m_resource m2m_dehydrated[m2m_key] = self.dehydrate_related(m2m_bundle, m2m_resource, for_list=for_list) return m2m_dehydrated
def hydrate(self, bundle): """ Takes data stored in the bundle for the field and returns it. Used for taking simple data and building a instance object. """ if self.readonly: return None if not bundle.data.has_key(self.instance_name): if self.attribute and getattr(bundle.obj, self.attribute, None): return getattr(bundle.obj, self.attribute) elif self.instance_name and hasattr(bundle.obj, self.instance_name): return getattr(bundle.obj, self.instance_name) elif self.has_default(): if callable(self._default): return self._default() return self._default elif self.null: return None else: raise ApiFieldError( "The '%s' field has no data and doesn't allow a default or null value." % self.instance_name) return bundle.data[self.instance_name]
def hydrate_m2m(self, bundle): if self.readonly: return None if bundle.data.get(self.instance_name) is None: if self.blank: return [] elif self.null: return [] else: raise ApiFieldError( "The '%s' field has no data and doesn't allow a null value." % self.instance_name) m2m_hydrated = [] for value in bundle.data.get(self.instance_name): if value is None: continue kwargs = { 'request': bundle.request, } if self.related_name: kwargs['related_obj'] = bundle.obj kwargs['related_name'] = self.related_name m2m_hydrated.append(self.build_related_resource(value, **kwargs)) return m2m_hydrated
def hydrate(self, bundle): """ Takes data stored in the bundle for the field and returns it. Used for taking simple data and building a instance object. """ if self.readonly: return None if not bundle.data.has_key(self.instance_name): if getattr(self, 'is_related', False) and not getattr(self, 'is_m2m', False): # We've got an FK (or alike field) & a possible parent object. # Check for it. if bundle.related_obj and bundle.related_name in ( self.attribute, self.instance_name): return bundle.related_obj if self.blank: return None elif self.attribute and getattr(bundle.obj, self.attribute, None): return getattr(bundle.obj, self.attribute) elif self.instance_name and hasattr(bundle.obj, self.instance_name): return getattr(bundle.obj, self.instance_name) elif self.has_default(): if callable(self._default): return self._default() return self._default elif self.null: return None else: raise ApiFieldError( "The '%s' field has no data and doesn't allow a default or null value." % self.instance_name) return bundle.data[self.instance_name]
def dehydrate(self, bundle, for_list=True): """ Takes data from the provided object and prepares it for the resource. """ if self.attribute is not None: current_object = bundle.obj for attr in self._attrs: previous_object = current_object current_object = getattr(current_object, attr, None) if current_object is None: if self.has_default(): current_object = self._default # Fall out of the loop, given any further attempts at # accesses will fail miserably. break elif self.null: current_object = None # Fall out of the loop, given any further attempts at # accesses will fail miserably. break else: raise ApiFieldError("The object '%r' has an empty attribute '%s' and doesn't allow a default or null value." % (previous_object, attr)) if callable(current_object): current_object = current_object() return self.convert(current_object) if self.has_default(): return self.convert(self.default) else: return None
def dehydrate(self, bundle): foreign_obj = None depth = getattr(bundle, 'depth', 0) if isinstance(self.attribute, basestring): attrs = self.attribute.split('__') foreign_obj = bundle.obj for attr in attrs: previous_obj = foreign_obj try: foreign_obj = getattr(foreign_obj, attr, None) except ObjectDoesNotExist: foreign_obj = None elif callable(self.attribute): foreign_obj = self.attribute(bundle) if not foreign_obj: if not self.null: raise ApiFieldError( "The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr)) return None self.fk_resource = self.get_related_resource(foreign_obj) fk_bundle = Bundle(obj=foreign_obj, request=bundle.request) fk_bundle.depth = depth + 1 return self.dehydrate_related(fk_bundle, self.fk_resource)
def build_related_resource(self, value, request=None, related_obj=None, related_name=None): """ Returns a bundle of data built by the related resource, usually via ``hydrate`` with the data provided. Accepts either a URI, a data dictionary (or dictionary-like structure) or an object with a ``pk``. """ self.fk_resource = self.to_class() kwargs = { 'request': request, 'related_obj': related_obj, 'related_name': related_name, } if isinstance(value, basestring): # We got a URI. Load the object and assign it. return self.resource_from_uri(self.fk_resource, value, **kwargs) elif hasattr(value, 'items'): # We've got a data dictionary. # Since this leads to creation, this is the only one of these # methods that might care about "parent" data. return self.resource_from_data(self.fk_resource, value, **kwargs) elif hasattr(value, 'pk'): # We've got an object with a primary key. return self.resource_from_pk(self.fk_resource, value, **kwargs) else: raise ApiFieldError( "The '%s' field has was given data that was not a URI, not a dictionary-alike and does not have a 'pk' attribute: %s." % (self.instance_name, value))
def dehydrate(self, bundle, for_list=True): if not bundle.obj or not bundle.obj.pk: if not self.null: raise ApiFieldError( "The model '%r' does not have a primary key and can not be used in a ToMany context." % bundle.obj) return [] the_m2ms = None previous_obj = bundle.obj attr = self.attribute if callable(self.attribute): the_m2ms = self.attribute(bundle) elif isinstance(self.attribute, six.string_types): the_m2ms = bundle.obj for attr in self._attrs: previous_obj = the_m2ms try: the_m2ms = getattr(the_m2ms, attr, None) except ObjectDoesNotExist: the_m2ms = None if not the_m2ms: break if not the_m2ms: if not self.null: raise ApiFieldError( "The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr)) return [] if isinstance(the_m2ms, models.Manager): the_m2ms = the_m2ms.all() m2m_dehydrated = [ self.dehydrate_related(Bundle(obj=m2m, request=bundle.request), self.get_related_resource(m2m), for_list=for_list) for m2m in the_m2ms ] return m2m_dehydrated
def hydrate(self, bundle): if bundle.data.get(self.instance_name) is None: if self.null: return None else: raise ApiFieldError("The '%s' field has no data and doesn't allow a null value." % self.instance_name) return self.build_related_resource(bundle.data.get(self.instance_name))
def hydrate_project(self, bundle): if "project" not in bundle.data or "slug" not in bundle.data[ "project"] or "lang" not in bundle.data["project"]: raise ApiFieldError("A picture must be attached to a project") project = bundle.data["project"] try: project = I4pProjectTranslation.objects.get( slug=project["slug"], language_code=project["lang"], master__in=I4pProject.on_site.all()) except: raise ApiFieldError("Unable to find associated project") project = project.master bundle.obj.project = project return bundle
def save(self, bundle, skip_errors=False): obj = self.content_object.hydrate(bundle).obj if Invite.objects.filter( recipient=self.recipient.hydrate(bundle).obj, content_type=ContentType.objects.get_for_model(obj), object_id=obj.id).exists(): raise ApiFieldError("用户邀请") return super(InviteResource, self).save(bundle, skip_errors)
def resource_from_data(self, fk_resource, data, request=None, related_obj=None, related_name=None): """ Given a dictionary-like structure is provided, a fresh related resource is created using that data. """ # Try to hydrate the data provided. data = dict_strip_unicode_keys(data) fk_bundle = fk_resource.build_bundle(data=data, request=request) if related_obj: fk_bundle.related_obj = related_obj fk_bundle.related_name = related_name # We need to check to see if updates are allowed on the FK # resource. If not, we'll just return a populated bundle instead # of mistakenly updating something that should be read-only. if not fk_resource.can_update(): # If the resource already exists and the client specified where to find it, we look it up. if 'resource_uri' in data: obj = fk_resource.get_via_uri(data['resource_uri'], request=request) fk_bundle.install_existing_obj(obj) return fk_bundle # If the resource supports creation, then we can full_hydrate() and create a new instance. elif fk_resource.can_create(): return fk_resource.full_hydrate(fk_bundle) else: raise ApiFieldError( "Resource %s does not support being created via POST" % fk_resource._meta.resource_name) try: return fk_resource.obj_update(fk_bundle, **data) except NotFound: try: # Attempt lookup by primary key lookup_kwargs = dict((k, v) for k, v in data.iteritems() if getattr(fk_resource, k).unique) if not lookup_kwargs: raise NotFound() return fk_resource.obj_update(fk_bundle, **lookup_kwargs) except NotFound: fk_bundle = fk_resource.full_hydrate(fk_bundle) fk_resource.is_valid(fk_bundle, request) return fk_bundle except MultipleObjectsReturned: return fk_resource.full_hydrate(fk_bundle)