예제 #1
0
    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)
예제 #2
0
    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
예제 #3
0
    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)
예제 #4
0
    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)
예제 #5
0
    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
예제 #6
0
 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
예제 #7
0
 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
예제 #8
0
 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)
예제 #9
0
    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
예제 #10
0
 def auth_post_detail(self, request, *args, **kwargs):
     response = self.create_json_response(py_obj='', status=405)
     raise HttpInterrupt(response)
예제 #11
0
 def forbidden(self):
     response = HttpResponse('',
                             status=403,
                             content_type='application/json')
     raise HttpInterrupt(response)