Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
vachan-maker
funkwhale
Commits
d50cce36
Unverified
Commit
d50cce36
authored
Jun 22, 2020
by
Agate
💬
Browse files
Added a new ?related=obj_id filter for artists, albums and tracks, based on tags
parent
ae781904
Changes
5
Hide whitespace changes
Inline
Side-by-side
api/funkwhale_api/music/filters.py
View file @
d50cce36
...
...
@@ -9,6 +9,7 @@ from funkwhale_api.common import fields
from
funkwhale_api.common
import
filters
as
common_filters
from
funkwhale_api.common
import
search
from
funkwhale_api.moderation
import
filters
as
moderation_filters
from
funkwhale_api.tags
import
filters
as
tags_filters
from
.
import
models
from
.
import
utils
...
...
@@ -24,6 +25,28 @@ def filter_tags(queryset, name, value):
TAG_FILTER
=
common_filters
.
MultipleQueryFilter
(
method
=
filter_tags
)
class
RelatedFilterSet
(
filters
.
FilterSet
):
related_type
=
int
related_field
=
"pk"
related
=
filters
.
CharFilter
(
field_name
=
"_"
,
method
=
"filter_related"
)
def
filter_related
(
self
,
queryset
,
name
,
value
):
if
not
value
:
return
queryset
.
none
()
try
:
pk
=
self
.
related_type
(
value
)
except
(
TypeError
,
ValueError
):
return
queryset
.
none
()
try
:
obj
=
queryset
.
model
.
objects
.
get
(
**
{
self
.
related_field
:
pk
})
except
queryset
.
model
.
DoesNotExist
:
return
queryset
.
none
()
queryset
=
queryset
.
exclude
(
pk
=
obj
.
pk
)
return
tags_filters
.
get_by_similar_tags
(
queryset
,
obj
.
get_tags
())
class
ChannelFilterSet
(
filters
.
FilterSet
):
channel
=
filters
.
CharFilter
(
field_name
=
"_"
,
method
=
"filter_channel"
)
...
...
@@ -70,6 +93,7 @@ class LibraryFilterSet(filters.FilterSet):
class
ArtistFilter
(
RelatedFilterSet
,
LibraryFilterSet
,
audio_filters
.
IncludeChannelsFilterSet
,
moderation_filters
.
HiddenContentFilterSet
,
...
...
@@ -88,6 +112,7 @@ class ArtistFilter(
(
"creation_date"
,
"creation_date"
),
(
"modification_date"
,
"modification_date"
),
(
"?"
,
"random"
),
(
"tag_matches"
,
"related"
),
)
)
...
...
@@ -109,6 +134,7 @@ class ArtistFilter(
class
TrackFilter
(
RelatedFilterSet
,
ChannelFilterSet
,
LibraryFilterSet
,
audio_filters
.
IncludeChannelsFilterSet
,
...
...
@@ -140,6 +166,7 @@ class TrackFilter(
(
"artist__name"
,
"artist__name"
),
(
"artist__modification_date"
,
"artist__modification_date"
),
(
"?"
,
"random"
),
(
"tag_matches"
,
"related"
),
)
)
...
...
@@ -217,6 +244,7 @@ class UploadFilter(audio_filters.IncludeChannelsFilterSet):
class
AlbumFilter
(
RelatedFilterSet
,
ChannelFilterSet
,
LibraryFilterSet
,
audio_filters
.
IncludeChannelsFilterSet
,
...
...
@@ -239,6 +267,7 @@ class AlbumFilter(
(
"title"
,
"title"
),
(
"artist__modification_date"
,
"artist__modification_date"
),
(
"?"
,
"random"
),
(
"tag_matches"
,
"related"
),
)
)
...
...
api/funkwhale_api/tags/filters.py
View file @
d50cce36
from
django.db
import
models
as
dj_models
import
django_filters
from
django_filters
import
rest_framework
as
filters
...
...
@@ -19,3 +21,19 @@ class TagFilter(filters.FilterSet):
class
Meta
:
model
=
models
.
Tag
fields
=
{
"q"
:
[
"exact"
],
"name"
:
[
"exact"
,
"startswith"
]}
def
get_by_similar_tags
(
qs
,
tags
):
"""
Return a queryset of obects with at least one matching tag.
Annotate the queryset so you can order later by number of matches.
"""
qs
=
qs
.
filter
(
tagged_items__tag__name__in
=
tags
).
annotate
(
tag_matches
=
dj_models
.
Count
(
dj_models
.
Case
(
dj_models
.
When
(
tagged_items__tag__name__in
=
tags
,
then
=
1
),
output_field
=
dj_models
.
IntegerField
(),
)
)
)
return
qs
.
distinct
()
api/tests/music/test_filters.py
View file @
d50cce36
...
...
@@ -203,3 +203,41 @@ def test_track_filter_artist_includes_album_artist(
)
assert
filterset
.
qs
==
[
track2
,
track1
]
@
pytest
.
mark
.
parametrize
(
"factory_name, filterset_class"
,
[
(
"music.Track"
,
filters
.
TrackFilter
),
(
"music.Artist"
,
filters
.
ArtistFilter
),
(
"music.Album"
,
filters
.
AlbumFilter
),
],
)
def
test_filter_tag_related
(
factory_name
,
filterset_class
,
factories
,
anonymous_user
,
queryset_equal_list
,
mocker
,
):
factories
[
"tags.Tag"
](
name
=
"foo"
)
factories
[
"tags.Tag"
](
name
=
"bar"
)
factories
[
"tags.Tag"
](
name
=
"baz"
)
factories
[
"tags.Tag"
]()
factories
[
"tags.Tag"
]()
matches
=
[
factories
[
factory_name
](
set_tags
=
[
"foo"
,
"bar"
,
"baz"
,
"noop"
]),
factories
[
factory_name
](
set_tags
=
[
"foo"
,
"baz"
,
"noop"
]),
factories
[
factory_name
](
set_tags
=
[
"baz"
,
"noop"
]),
]
factories
[
factory_name
](
set_tags
=
[
"noop"
]),
obj
=
factories
[
factory_name
](
set_tags
=
[
"foo"
,
"bar"
,
"baz"
])
filterset
=
filterset_class
(
{
"related"
:
obj
.
pk
,
"ordering"
:
"-related"
},
request
=
mocker
.
Mock
(
user
=
anonymous_user
,
actor
=
None
),
queryset
=
obj
.
__class__
.
objects
.
all
(),
)
assert
filterset
.
qs
==
matches
changes/changelog.d/1145.enhancement
0 → 100644
View file @
d50cce36
Support ordering=random for artists, albums, tracks and channels endpoints (#1145)
changes/changelog.d/api-related.enhancement
0 → 100644
View file @
d50cce36
Added a new ?related=obj_id filter for artists, albums and tracks, based on tags
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment