django_api/decorators.py
def api_accepts(fields):
    """
    Define the accept schema of an API (GET or POST).

    'fields' is a dict of Django form fields keyed by field name that specifies
    the form-urlencoded fields that the API accepts*.

    The view function is then called with GET/POST data that has been cleaned
    by the Django form.

    In debug and test modes, failure to validate the fields will result in a
    400 Bad Request response.
    In production mode, failure to validate will just log a
    warning, unless overwritten by a 'strict' setting.

    For example:

    @api_accepts({
        'x': forms.IntegerField(min_value=0),
        'y': forms.IntegerField(min_value=0),
    })
    def add(request, *args, **kwargs):
        x = request.POST['x']
        y = request.POST['y']

        # x and y are integers already.
        return HttpResponse('%d' % (x + y))


    *: 'fields' can also include Django models as {'key': Model()}. If present,
    api_accepts will look for the field keyed by '<key>-id'
    and pick the object that has that primary key. For example, if the entry is
    {'course': Course()}, it will search for the key course_id='course-id' in
    the request object, and find the object Course.objects.get(pk=course_id)
    """
    def decorator(func):
        @wraps(func)
        def wrapped_func(request, *args, **kwargs):
            if request.method not in ['GET', 'POST']:
                return func(request, *args, **kwargs)

            # The fields dict passed into the type() function is modified, so
            # send in a copy instead.
            form_class = type('ApiForm', (forms.Form,), fields.copy())
            form = form_class(getattr(request, request.method))

            if not form.is_valid():
                if settings.DEBUG:
                    return JsonResponseBadRequest(
                        'failed to validate: %s' % dict(form.errors)
                    )
                else:
                    logger.warn(
                        'input to \'%s\' failed to validate: %s',
                        request.path,
                        dict(form.errors)
                    )
                    return func(request, *args, **kwargs)

            # Clean any models.Model fields, by looking up object based on
            # primary key in request.
            for (field_name, field_instance) in fields.items():
                if isinstance(field_instance, models.Model):
                    field_type = type(field_instance)
                    # TODO: irregular, should we remove?
                    field_id = '%s-id' % field_name
                    if field_id not in request.REQUEST:
                        return JsonResponseBadRequest(
                            'field %s not present' % field_name
                        )
                    field_pk = int(request.REQUEST[field_id])
                    try:
                        field_value = field_type.objects.get(pk=field_pk)
                    except field_type.DoesNotExist:
                        return JsonResponseNotFound(
                            '%s with pk=%d does not exist' % (
                                field_type, field_pk
                            )
                        )
                    form.cleaned_data[field_name] = field_value

            validated_request = ValidatedRequest(request, form)
            return func(validated_request, *args, **kwargs)
        return wrapped_func
    return decorator
def api_accepts(fields):
    """
    Define the accept schema of an API (GET or POST).

    'fields' is a dict of Django form fields keyed by field name that specifies
    the form-urlencoded fields that the API accepts*.

    The view function is then called with GET/POST data that has been cleaned
    by the Django form.

    In debug and test modes, failure to validate the fields will result in a
    400 Bad Request response.
    In production mode, failure to validate will just log a
    warning, unless overwritten by a 'strict' setting.

    For example:

    @api_accepts({
        'x': forms.IntegerField(min_value=0),
        'y': forms.IntegerField(min_value=0),
    })
    def add(request, *args, **kwargs):
        x = request.POST['x']
        y = request.POST['y']

        # x and y are integers already.
        return HttpResponse('%d' % (x + y))


    *: 'fields' can also include Django models as {'key': Model()}. If present,
    api_accepts will look for the field keyed by '<key>-id'
    and pick the object that has that primary key. For example, if the entry is
    {'course': Course()}, it will search for the key course_id='course-id' in
    the request object, and find the object Course.objects.get(pk=course_id)
    """
    def decorator(func):
        @wraps(func)
        def wrapped_func(request, *args, **kwargs):
            if request.method not in ['GET', 'POST']:
                return func(request, *args, **kwargs)

            # The fields dict passed into the type() function is modified, so
            # send in a copy instead.
            form_class = type('ApiForm', (forms.Form,), fields.copy())
            form = form_class(getattr(request, request.method))

            if not form.is_valid():
                if settings.DEBUG:
                    return JsonResponseBadRequest(
                        'failed to validate: %s' % dict(form.errors)
                    )
                else:
                    logger.warn(
                        'input to \'%s\' failed to validate: %s',
                        request.path,
                        dict(form.errors)
                    )
                    return func(request, *args, **kwargs)

            # Clean any models.Model fields, by looking up object based on
            # primary key in request.
            for (field_name, field_instance) in fields.items():
                if isinstance(field_instance, models.Model):
                    field_type = type(field_instance)
                    # TODO: irregular, should we remove?
                    field_id = '%s-id' % field_name
                    if field_id not in request.REQUEST:
                        return JsonResponseBadRequest(
                            'field %s not present' % field_name
                        )
                    field_pk = int(request.REQUEST[field_id])
                    try:
                        field_value = field_type.objects.get(pk=field_pk)
                    except field_type.DoesNotExist:
                        return JsonResponseNotFound(
                            '%s with pk=%d does not exist' % (
                                field_type, field_pk
                            )
                        )
                    form.cleaned_data[field_name] = field_value

            validated_request = ValidatedRequest(request, form)
            return func(validated_request, *args, **kwargs)
        return wrapped_func
    return decorator
def api_accepts ( fields ) : def decorator ( func ) : @ wraps ( func ) def wrapped_func ( request , * args , * * kwargs ) : if request . method not in [ 'GET' , 'POST' ] : return func ( request , * args , * * kwargs ) # The fields dict passed into the type() function is modified, so # send in a copy instead. form_class = type ( 'ApiForm' , ( forms . Form , ) , fields . copy ( ) ) form = form_class ( getattr ( request , request . method ) ) if not form . is_valid ( ) : if settings . DEBUG : return JsonResponseBadRequest ( 'failed to validate: %s' % dict ( form . errors ) ) else : logger . warn ( 'input to \'%s\' failed to validate: %s' , request . path , dict ( form . errors ) ) return func ( request , * args , * * kwargs ) # Clean any models.Model fields, by looking up object based on # primary key in request. for ( field_name , field_instance ) in fields . items ( ) : if isinstance ( field_instance , models . Model ) : field_type = type ( field_instance ) # TODO: irregular, should we remove? field_id = '%s-id' % field_name if field_id not in request . REQUEST : return JsonResponseBadRequest ( 'field %s not present' % field_name ) field_pk = int ( request . REQUEST [ field_id ] ) try : field_value = field_type . objects . get ( pk = field_pk ) except field_type . DoesNotExist : return JsonResponseNotFound ( '%s with pk=%d does not exist' % ( field_type , field_pk ) ) form . cleaned_data [ field_name ] = field_value validated_request = ValidatedRequest ( request , form ) return func ( validated_request , * args , * * kwargs ) return wrapped_func return decorator
Define the accept schema of an API (GET or POST).

    'fields' is a dict of Django form fields keyed by field name that specifies
    the form-urlencoded fields that the API accepts*.

    The view function is then called with GET/POST data that has been cleaned
    by the Django form.

    In debug and test modes, failure to validate the fields will result in a
    400 Bad Request response.
    In production mode, failure to validate will just log a
    warning, unless overwritten by a 'strict' setting.

    For example:

    @api_accepts({
        'x': forms.IntegerField(min_value=0),
        'y': forms.IntegerField(min_value=0),
    })
    def add(request, *args, **kwargs):
        x = request.POST['x']
        y = request.POST['y']

        # x and y are integers already.
        return HttpResponse('%d' % (x + y))


    *: 'fields' can also include Django models as {'key': Model()}. If present,
    api_accepts will look for the field keyed by '<key>-id'
    and pick the object that has that primary key. For example, if the entry is
    {'course': Course()}, it will search for the key course_id='course-id' in
    the request object, and find the object Course.objects.get(pk=course_id)
Define the accept schema of an API ( GET or POST ) .