Skip to content
Snippets Groups Projects
Commit 4e6cef77 authored by martinburchell's avatar martinburchell
Browse files

Merge pull request #17 from aptivate/itemtable_filters

Add terms filtering to items API
parents f0cd0538 dda4103b
No related branches found
No related tags found
1 merge request!23Tabbed view header styling
......@@ -7,6 +7,8 @@ from taxonomies.tests.factories import TermFactory
from ..views import ItemViewSet
from .item_create_view_tests import create_item
from .taxonomy_and_term_create_tests import create_category, add_term
from .categorize_items_tests import categorize_item
def get(data=None):
......@@ -58,6 +60,59 @@ def test_filter_by_id_list():
assert len(payload) == 10
@pytest.mark.django_db
def test_filter_by_term():
taxonomy = create_category('taxonomy').data
term = add_term(taxonomy=taxonomy['slug'], name='term').data
items = [create_item(body='item %d' % i).data for i in range(3)]
# Only the first item is categorized
categorize_item(items[0], term)
term_filter = '{}:{}'.format(taxonomy['slug'], term['name'])
payload = get(data={'terms': [term_filter]}).data
assert len(payload) == 1
assert payload[0]['body'] == items[0]['body']
@pytest.mark.django_db
def test_filter_by_multiple_terms():
# TODO: Refactor to use the REST API when we can add
# multiple terms to an item
items = [ItemFactory() for i in range(3)]
terms = [TermFactory() for i in range(3)]
# All items are categorized with terms[0], only
# one item is categorized with terms[1]
for item in items:
item.terms.add(terms[0])
items[0].terms.add(terms[1])
term_filter = [
'{}:{}'.format(terms[0].taxonomy.slug, terms[0].name),
'{}:{}'.format(terms[1].taxonomy.slug, terms[1].name)
]
payload = get(data={'terms': term_filter}).data
assert len(payload) == 1
assert payload[0]['body'] == items[0].body
@pytest.mark.django_db
def test_filter_by_term_works_when_term_name_includes_colon():
taxonomy = create_category('taxonomy').data
term = add_term(taxonomy=taxonomy['slug'], name='term:with:colon').data
item = create_item(body='item 1').data
categorize_item(item, term)
term_filter = '{}:{}'.format(taxonomy['slug'], term['name'])
payload = get(data={'terms': [term_filter]}).data
assert len(payload) == 1
assert payload[0]['body'] == item['body']
@pytest.mark.django_db
def test_item_listed_with_associated_terms():
# TODO: Refactor to use the REST API when we can add
......
......@@ -28,11 +28,44 @@ class ItemViewSet(viewsets.ModelViewSet, BulkDestroyModelMixin):
filter_fields = ('created', 'body', 'timestamp', )
def get_queryset(self):
""" Return the queryset for this view.
This accepts two get parameters for filtering:
ids: A list of ids
terms: A list of strings formatted as
<taxonomy slug>:<term name>.
Notes:
- Only items that have all the given
terms are returned;
- taxonomy slugs do not allow ':'
characters, so no escaping is
needed.
Returns:
QuerySet: The filtered list of items
"""
items = Item.objects.all()
# Filter on ids
ids = self.request.query_params.getlist('ids')
if ids:
items = items.filter(id__in=ids)
# Filter on terms
terms = self.request.query_params.getlist('terms', [])
for taxonomy_and_term in terms:
(taxonomy, term) = taxonomy_and_term.split(':', 1)
matches = Term.objects.filter(
name=term, taxonomy__slug=taxonomy
)
if len(matches) == 0:
# If the term doesn't exist, there can be no matches
return Item.objects.none()
items = items.filter(terms__id=matches[0].id)
return items
@detail_route(methods=['post'])
......
......@@ -12,3 +12,27 @@ def test_taxonomies_have_a_slug():
taxonomy.save()
assert taxonomy.slug == "test-taxonomy"
@pytest.mark.django_db
def test_taxonomies_cannot_have_colon_in_slug():
""" It is important for the rest API item search
that taxonomy slugs do not contain colons
(so query parameters can be formated as
<taxonomy slug>:<term name>).
This test is added here to prevent regression.
"""
# Ensure colons are stripped when doing automatic
# slugs
taxonomy1 = Taxonomy(name="A taxonony with : colons")
taxonomy1.save()
assert ':' not in taxonomy1.slug
# Ensure attempting to force a colon in a slug fails
taxonomy2 = Taxonomy(name="A taxonomy with defined slug",
slug="a-slug-with:colon")
taxonomy2.save()
assert ':' not in taxonomy2.slug
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment