Search code examples
angularjsdjangodjango-rest-frameworkrestangular

Restangular query returns all items


My api is setup with Django Rest Framework and I feel like I am fighting with Django trailing slashes. There seems to be some combination that I have not figured out. A basic query always returns all the objects at the api endpoint.

Here's the code:

// App config
var App = angular.module('App',['App.controllers','restangular','ngRoute','ngResource']); 

App.config(function ($interpolateProvider, $httpProvider, $resourceProvider, RestangularProvider) {

    RestangularProvider.setBaseUrl('/api/');

    // Things I've tried
    RestangularProvider.setBaseUrl('http://127.0.0.1:8000/api/');
    RestangularProvider.setRequestSuffix('/');
    // with suffix http://127.0.0.1:8000/api/tests/?value=404
    // without suffix http://127.0.0.1:8000/api/tests?value=404
    $resourceProvider.defaults.stripTrailingSlashes = false;
});

// In controller
// Items in database
// [{"itemID": 1,"value": 5,},{"itemID": 2,"value": 404,},{"itemID": 3,"value": 73,}]

var params = {'value': 404};
Restangular.all('tests').getList(params).then(function(items) {
    var items = items
    console.log(items)
});

// Even the standard $resource does the same thing.
var Foo = $resource('/api/tests', {value:'@somevalue'}); 
$scope.allItems = {};
Foo.query({value:404}, function(items) {
    $scope.allItems = items;
});

I can see it trying to go to /tests?params but it faults over to tests/?params

"GET /api/tests?value=404 HTTP/1.1" 301 0
"GET /api/tests/?value=404 HTTP/1.1" 200 361

Maybe I'm structuring the query wrong? Is there a way to test queries by actually going to the address? Technically shouldn't navigating to http://127.0.0.1:8000/api/tests?value=404 bring up in DRF only the list of objects with a value of 404? DRF puts in the slash at the end of the url before the parameters (http://127.0.0.1:8000/api/tests/?value=404).

Does anyone have a tried and true method for working with Django Rest Framework?


Solution

  • Here's what I have figured out. Querying requires Django Rest Framework filtering. After installing django filter, you add filter_backends and filter_fields to your viewset. Good to go.

    $ pip install django-filter
    
    // In your serializers.py
    // Create your serializer
    from rest_framework import serializers
    class FoobarSerializer(serializers.ModelSerializer):
        class Meta:
            model = Foobar
            fields = ('foo','bar')
    
    
    // -----
    // In your main app urls.py (or wherever you put your viewset, I have them in urls so most api stuff is collected there)
    from rest_framework import routers
    from rest_framework import viewsets
    from rest_framework import filters
    from mainapp.serializers import FoobarSerializer
    from app.models import Foobar
    
    
    // Put your filter fields in your viewset
    class FoobarViewSet(viewsets.ModelViewSet):
        queryset = Foobar.objects.all()
        serializer_class = FoobarSerializer
        filter_backends = (filters.DjangoFilterBackend,)
        filter_fields = ('foo', 'bar')
    
    // Register the viewset
    router = routers.DefaultRouter()
    router.register(r'foobars', FoobarViewSet)
    urlpatterns = [
        ...
        url(r'^api/', include(router.urls)),
    ]
    
    // -----
    // In your angular controller.js
    // Restangular
    var params = {'foo': 404};
    Restangular.all('foobars').getList(params).then(function(items) {
        $scope.items = items
    });
    
    // $resource
    var Foo = $resource('/api/foobars', {value:'@somevalue'}); 
    Foo.query({value:404}, function(items) {
        $scope.items = items;
    });
    
    // $http
    $http({method:'GET',url:'/api/foobars',params:{value:404}}).then(function(response) {
        $scope.items = response.data;
    });