Repository: djangopackages/djangopackages

Issue:
Packages API should support filtering
Right now there is no way to get list of packages of a specific category. _Category_ resource does not contain list of resource_url of packages just like the _Grid_ resource does and there is no way to apply a filter on _Package_ resource.

Ideally the _Category_ resource should contain a list of packages like the _Grid_ resource does:

```
    packages: [
        "/api/v1/package/django-cms/"
        "/api/v1/package/django-page-cms/"
        "/api/v1/package/django-lfc/"
        "/api/v1/package/merengue/"
        "/api/v1/package/mezzanine/"
        "/api/v1/package/philo/"
        "/api/v1/package/pylucid/"
        "/api/v1/package/django-gitcms/"
        "/api/v1/package/django-simplepages/"
        "/api/v1/package/djpcms/"
        "/api/v1/package/feincms/"
    ]
```

Furthermore, there should be a filter on _Package_ resource like this:

`/package/?category=apps`



Discussion:
I am attempting to fix this myself.


Resolving patch:
diff --git a/apiv1/resources.py b/apiv1/resources.py
--- a/apiv1/resources.py
+++ b/apiv1/resources.py
@@ -10,7 +10,7 @@
 from tastypie import fields
 from tastypie.bundle import Bundle
 from tastypie.exceptions import NotFound
-from tastypie.resources import ModelResource
+from tastypie.resources import ModelResource, ALL_WITH_RELATIONS
 
 from grid.models import Grid
 from homepage.models import Dpotw, Gotw
@@ -209,3 +209,6 @@ class Meta:
         allowed_methods = ['get']
         include_absolute_url = True
         lookup_field = 'slug'
+        filtering = {
+            "category": ALL_WITH_RELATIONS
+        }
diff --git a/urls.py b/urls.py
--- a/urls.py
+++ b/urls.py
@@ -43,12 +43,10 @@
 from apiv1.resources import (
                     GotwResource, DpotwResource,
                     PackageResource, CategoryResource,
-                    GridResource, PackageResourceBase,
-                    UserResource
+                    GridResource, UserResource
                     )
 
 v1_api = Api()
-v1_api.register(PackageResourceBase())
 v1_api.register(PackageResource())
 v1_api.register(CategoryResource())
 v1_api.register(GridResource())


Test patch:
diff --git a/apiv1/tests/test_package.py b/apiv1/tests/test_package.py
--- a/apiv1/tests/test_package.py
+++ b/apiv1/tests/test_package.py
@@ -4,6 +4,7 @@
 from grid.models import Grid, GridPackage
 from package.models import Package, Category
 import json
+import urllib
 
 
 class PackageV1Tests(TestCase):
@@ -12,10 +13,14 @@ def setUp(self):
         Set up initial data, done through Python because fixtures break way too
         quickly with migrations and are terribly hard to maintain.
         """
-        app = Category.objects.create(
+        self.app = Category.objects.create(
             title='App',
             slug='app',
         )
+        self.framework = Category.objects.create(
+            title='Framework',
+            slug='framework',
+        )
         self.grid = Grid.objects.create(
             title='A Grid',
             slug='grid',
@@ -23,15 +28,21 @@ def setUp(self):
         self.pkg1 = Package.objects.create(
             title='Package1',
             slug='package1',
-            category=app,
+            category=self.app,
             repo_url='https://github.com/pydanny/django-uni-form'
         )
         self.pkg2 = Package.objects.create(
             title='Package2',
             slug='package2',
-            category=app,
+            category=self.app,
             repo_url='https://github.com/cartwheelweb/packaginator'  
         )
+        self.pkg3 = Package.objects.create(
+            title='Package3',
+            slug='package3',
+            category=self.framework,
+            repo_url='https://github.com/divio/django-cms'
+        )
         GridPackage.objects.create(package=self.pkg1, grid=self.grid)
         GridPackage.objects.create(package=self.pkg2, grid=self.grid)
         user = User.objects.create_user('user', 'user@packaginator.com', 'user')
@@ -67,4 +78,27 @@ def test_01_packages_usage(self):
         raw_json_pkg2 = response_pkg2.content
         pkg_2 = json.loads(raw_json_pkg2)
         usage_count_pkg2 = int(pkg_2['usage_count'])
-        self.assertEqual(usage_count_pkg2, self.pkg2.usage.count())
\ No newline at end of file
+        self.assertEqual(usage_count_pkg2, self.pkg2.usage.count())
+
+    def test_02_category_packages(self):
+        urlkwargs_pkg_list = {
+            'api_name': 'v1',
+            'resource_name': 'package',
+        }
+        querystring_filter_app = {
+            'category__slug': self.app.slug
+        }
+        url_app_pkg = "%s?%s" % (reverse('api_dispatch_list',
+            kwargs=urlkwargs_pkg_list), urllib.urlencode(querystring_filter_app))
+        response_app_pkg = self.client.get(url_app_pkg)
+        # check that the request was successful
+        self.assertEqual(response_app_pkg.status_code, 200)
+        # check that we have correct number of packages in filter
+        raw_json_app_pkg = response_app_pkg.content
+        app_pkg = json.loads(raw_json_app_pkg)
+        app_pkg_count = int(app_pkg['meta']['total_count'])
+        self.assertEqual(app_pkg_count, self.app.package_set.count())
+        # Check that we have filter applied correclty
+        app_package_slug_list = self.app.package_set.values_list('slug', flat=True)
+        self.assertIn(self.pkg1.slug, app_package_slug_list)
+        self.assertIn(self.pkg2.slug, app_package_slug_list)
diff --git a/apiv1/tests/test_resources.py b/apiv1/tests/test_resources.py
--- a/apiv1/tests/test_resources.py
+++ b/apiv1/tests/test_resources.py
@@ -21,6 +21,9 @@ def test_01_category(self):
         self.assertTrue(cat_url in response.content)
         response = self.client.get(cat_url)
         self.assertEqual(response.status_code, 200)
+        query_filter = "?category__slug=apps"
+        cat_filter_url = "%s%s" % (list_url, query_filter)
+        self.assertEqual(response.status_code, 200)
         
     def test_02_grid(self):
         kwargs = {'resource_name': 'grid'}
@@ -34,3 +37,16 @@ def test_02_grid(self):
         self.assertTrue(grid_url in response.content)
         response = self.client.get(grid_url)
         self.assertEqual(response.status_code, 200)
+
+    def test_03_package(self):
+        kwargs = {'resource_name': 'package'}
+        kwargs.update(self.base_kwargs)
+        # check 200's
+        list_url = reverse('api_dispatch_list', kwargs=kwargs)
+        response = self.client.get(list_url)
+        self.assertEqual(response.status_code, 200)
+        kwargs['pk'] = 'testability'
+        package_url = reverse('api_dispatch_detail', kwargs=kwargs)
+        self.assertTrue(package_url in response.content)
+        response = self.client.get(package_url)
+        self.assertEqual(response.status_code, 200)