Skip to content

Commit 26765fc

Browse files
API: add project name/slug filters (#9843)
* API: add project name/slug filters I am trying to use the project API for some search and dropdown filters, and while I can filter the local results, it's much nicer to use the API filter for this. This adds an icontains filter field for project name and slug, and hopefully some accurate tests. * Lint * Add missing fixture * Remove print statement Co-authored-by: Benjamin Balder Bach <[email protected]> * Add comment on changing filter fields Co-authored-by: Benjamin Balder Bach <[email protected]>
1 parent a8e8827 commit 26765fc

File tree

4 files changed

+61
-2
lines changed

4 files changed

+61
-2
lines changed

docs/user/api/v3.rst

+2
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ Projects list
186186
}]
187187
}
188188

189+
:query string name: return projects with matching name
190+
:query string slug: return projects with matching slug
189191
:query string language: language code as ``en``, ``es``, ``ru``, etc.
190192
:query string programming_language: programming language code as ``py``, ``js``, etc.
191193

readthedocs/api/v3/filters.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,20 @@
88

99
class ProjectFilter(filters.FilterSet):
1010

11+
# TODO this is copying the patterns from other filter sets, where the fields
12+
# are all ``icontains`` lookups by default. We discussed reversing this
13+
# pattern in the future though, see:
14+
# https://github.com/readthedocs/readthedocs.org/issues/9862
15+
name = filters.CharFilter(lookup_expr="icontains")
16+
slug = filters.CharFilter(lookup_expr="icontains")
17+
1118
class Meta:
1219
model = Project
1320
fields = [
14-
'language',
15-
'programming_language',
21+
"name",
22+
"slug",
23+
"language",
24+
"programming_language",
1625
]
1726

1827

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"count": 0,
3+
"next": null,
4+
"previous": null,
5+
"results": []
6+
}

readthedocs/api/v3/tests/test_projects.py

+42
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,48 @@ def test_projects_list(self):
2323
self._get_response_dict('projects-list'),
2424
)
2525

26+
def test_projects_list_filter_full_hit(self):
27+
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
28+
response = self.client.get(
29+
reverse("projects-list"),
30+
data={
31+
"name": self.project.name,
32+
},
33+
)
34+
self.assertEqual(response.status_code, 200)
35+
self.assertDictEqual(
36+
response.json(),
37+
self._get_response_dict("projects-list"),
38+
)
39+
40+
def test_projects_list_filter_partial_hit(self):
41+
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
42+
response = self.client.get(
43+
reverse("projects-list"),
44+
data={
45+
"name": self.project.name[0:3],
46+
},
47+
)
48+
self.assertEqual(response.status_code, 200)
49+
self.assertDictEqual(
50+
response.json(),
51+
self._get_response_dict("projects-list"),
52+
)
53+
54+
def test_projects_list_filter_miss(self):
55+
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
56+
response = self.client.get(
57+
reverse("projects-list"),
58+
data={
59+
"name": "63dadecd5323d789cafe09f01cda85fd",
60+
},
61+
)
62+
self.assertEqual(response.status_code, 200)
63+
self.assertDictEqual(
64+
response.json(),
65+
self._get_response_dict("projects-list-empty"),
66+
)
67+
2668
def test_own_projects_detail(self):
2769
self.client.credentials(HTTP_AUTHORIZATION=f'Token {self.token.key}')
2870
response = self.client.get(

0 commit comments

Comments
 (0)