def process_filters(self, request, *args, **kwargs): """ Grab filters from request params and create final list of ORM filters Request filters will be checked against allowed_filters and added to default_filters to create final list. """ # Collect and check filters coming in through request get_params = request.GET.copy() # Remove special filters order_by = get_params.get('order_by', self.Meta.default_ordering) get_params.pop('order_by', None) if order_by: if (order_by not in self.Meta.allowed_ordering) and ( order_by != self.Meta.default_ordering): message = { '__all__': '{0} is not a valid ordering'.format(order_by) } response = self.create_json_response(py_obj=message, status=400) raise HttpInterrupt(response) kwargs['order_by'] = order_by limit = int(get_params.get('limit', self.Meta.default_limit)) get_params.pop('limit', None) if limit: if (limit > self.Meta.max_limit): message = { '__all__': '{0} is higher than max limit of {1}'.format( limit, self.Meta.max_limit) } response = self.create_json_response(py_obj=message, status=400) raise HttpInterrupt(response) kwargs['limit'] = limit offset = int(get_params.get('offset', 0)) get_params.pop('offset', None) kwargs['offset'] = offset # Add default filters filters = {} filters.update(self.Meta.default_filters) # Update from request filters for key, value in six.iteritems(get_params): if key not in self.Meta.allowed_filters: message = { '__all__': '{0} is not an allowed filter'.format(key) } response = self.create_json_response(py_obj=message, status=400) raise HttpInterrupt(response) else: filters[key] = value kwargs['filters'] = filters return (request, args, kwargs)
def save_gfk_objs(self, request, *args, **kwargs): for bundle in kwargs['bundles']: obj = bundle['obj'] request_data = bundle['request_data'] # GFKs must be explicitly stated on Resource gfk_fieldnames = self._get_explicit_field_by_type('gfk') for fieldname in gfk_fieldnames: related_data = request_data[fieldname] conduit_field = self._get_explicit_field_by_attribute( fieldname) if conduit_field: try: conduit_field.save_related(request, self, obj, related_data) except HttpInterrupt as e: error_dict = { fieldname: json.loads(e.response.content) } response = self.create_json_response( py_obj=error_dict, status=e.response.status_code) raise HttpInterrupt(response) return request, args, kwargs
def form_validate(self, request, *args, **kwargs): """ Validates request data with a provided Django form If the model object exists, it will pass it in to the form instance. If the form produces errors, a response is returned with a JSON representation of the errors. """ form_class = getattr(self.Meta, 'form_class', None) if form_class: fieldnames = self._get_model_fields() for bundle in kwargs['bundles']: data_copy = bundle['request_data'].copy() # Remove extra fields before validating forms # Such as resource_uri for key in list(data_copy.keys()): if key not in fieldnames: del data_copy[key] if 'obj' in bundle: form = self.Meta.form_class(data_copy, instance=bundle['obj']) else: form = self.Meta.form_class(data_copy) if not form.is_valid(): response = self.create_json_response(py_obj=form.errors, status=400) raise HttpInterrupt(response) return (request, args, kwargs)
def form_validate(self, request, *args, **kwargs): form_class = getattr(self.Meta, 'form_class', None) if form_class: fieldnames = self._get_model_fields() for bundle in kwargs['bundles']: data_copy = bundle['request_data'].copy() # Remove extra fields before validating forms # Such as resource_uri for key in list(data_copy.keys()): if key not in fieldnames: del data_copy[key] if 'obj' in bundle: form = self.Meta.form_class(data_copy, instance=bundle['obj']) else: form = self.Meta.form_class(data_copy) if not form.is_valid(): response = self.create_json_response(py_obj=form.errors, status=400) raise HttpInterrupt(response) return (request, args, kwargs)
def save_m2m_objs(self, request, *args, **kwargs): """ Adds or removes m2m objects to/from parent object. If m2m field is embed=True, will update m2m attributes or create new m2m objects """ ## Must be done after persisting parent objects for bundle in kwargs['bundles']: obj = bundle['obj'] request_data = bundle['request_data'] # Get all M2M fields on the Model m2m_fieldnames = self._get_type_fieldnames(obj, models.ManyToManyField) # Get explicit m2m fields which are not Model fields m2m_fieldnames.extend(self._get_explicit_field_by_type('m2m')) m2m_fieldnames = set(m2m_fieldnames) for fieldname in m2m_fieldnames: # Get the data to process related_data = request_data[fieldname] # If we are using a related resource field, use it conduit_field = self._get_explicit_field_by_attribute( fieldname) if conduit_field: try: conduit_field.save_related(request, self, obj, related_data) except HttpInterrupt as e: # Raise the error but specify it as occuring within # the related field error_dict = { fieldname: json.loads(e.response.content) } response = self.create_json_response( py_obj=error_dict, status=e.response.status_code) raise HttpInterrupt(response) # Otherwise we do it simply with primary keys else: related_manager = getattr(obj, fieldname) # Remove any pk's not included in related_data for attached_pk in related_manager.all().values_list( 'pk', flat=True): if attached_pk not in related_data: related_manager.remove(attached_pk) # Add all pk's included in related_data for related_pk in related_data: related_manager.add(related_pk) return request, args, kwargs
def bundles_from_request_data(self, request, *args, **kwargs): """ Form pairings of request data and new or existing objects Stores in bundles and objs lists. """ bundles = [] objs = [] pk_field = getattr(self.Meta, 'pk_field', 'id') for data in kwargs['request_data']: data_dict = data.copy() if 'put' in kwargs['pub']: # Updating existing object, so fetch it try: obj = self.Meta.model.objects.get( **{pk_field: data_dict[pk_field]}) except self.Meta.model.DoesNotExist: message = { '__all__': '{0} with key {1} does not exist'.format( self.Meta.model, data_dict[pk_field]) } response = self.create_json_response(py_obj=message, status=400) raise HttpInterrupt(response) except KeyError: message = {'__all__': 'Data set missing id or key'} response = self.create_json_response(py_obj=message, status=400) raise HttpInterrupt(response) else: obj = self.Meta.model() bundle = {} bundle['request_data'] = data_dict bundle['obj'] = obj bundles.append(bundle) objs.append(obj) kwargs['bundles'] = bundles kwargs['objs'] = objs return request, args, kwargs
def check_allowed_methods(self, request, *args, **kwargs): allowed_methods = getattr(self.Meta, 'allowed_methods', ['get', 'put', 'post', 'delete']) for keyword in kwargs['pub']: if keyword in ['get', 'put', 'post', 'delete' ] and keyword not in allowed_methods: message = { '__all__': '{0} Method Not Allowed'.format(keyword.upper()) } response = self.create_json_response(py_obj=message, status=405) raise HttpInterrupt(response) return request, args, kwargs
def get_object_from_kwargs(self, request, *args, **kwargs): """ Retrieve instance of model referenced by url kwargs """ cls = self.Meta.model try: kwds = {self.Meta.pk_field: kwargs[self.Meta.pk_field]} instance = cls.objects.get(**kwds) except cls.DoesNotExist: message = {'__all__': 'Object does not exist'} response = self.create_json_response(py_obj=message, status=404) raise HttpInterrupt(response) kwargs['objs'] = [instance] return (request, args, kwargs)
def save_fk_objs(self, request, *args, **kwargs): """ Updates and saves ForeignKey objects from hydrated request data. If embed=True, the FK object will be updated or created here. ForeignKey objects must be created and attached to the parent obj before saving the parent object, since the field may not be nullable """ for bundle in kwargs['bundles']: obj = bundle['obj'] request_data = bundle['request_data'] # Get all ForeignKey fields on the Model fk_fieldnames = self._get_type_fieldnames(obj, models.ForeignKey) # Get explicit FK fields which are not Model fields fk_fieldnames.extend(self._get_explicit_field_by_type('fk')) # Make sure names are unique fk_fieldnames = set(fk_fieldnames) for fieldname in fk_fieldnames: # Get the data to process related_data = request_data[fieldname] # If we are using a related resource field, use it conduit_field = self._get_explicit_field_by_attribute( fieldname) if conduit_field: try: conduit_field.save_related(request, self, obj, related_data) except HttpInterrupt as e: # Raise the error but specify it as occuring within # the related field error_dict = { fieldname: json.loads(e.response.content) } response = self.create_json_response( py_obj=error_dict, status=e.response.status_code) raise HttpInterrupt(response) # Otherwise we do it simply with primary keys else: id_fieldname = '{0}_id'.format(fieldname) setattr(obj, id_fieldname, related_data) return request, args, kwargs
def auth_post_detail(self, request, *args, **kwargs): response = self.create_json_response(py_obj='', status=405) raise HttpInterrupt(response)
def forbidden(self): response = HttpResponse('', status=403, content_type='application/json') raise HttpInterrupt(response)