UI To manage artists, albums, tracks

This commit is contained in:
Eliot Berriot 2019-04-17 14:17:59 +02:00
parent ae390e5c1c
commit b4731928fc
39 changed files with 2837 additions and 116 deletions

View file

@ -49,6 +49,6 @@ class SmartSearchFilter(django_filters.CharFilter):
return qs
try:
cleaned = self.config.clean(value)
except forms.ValidationError:
except (forms.ValidationError):
return qs.none()
return search.apply(qs, cleaned)

View file

@ -104,6 +104,31 @@ class MultipleQueryFilter(filters.TypedMultipleChoiceFilter):
self.lookup_expr = "in"
def filter_target(value):
config = {
"artist": ["artist", "target_id", int],
"album": ["album", "target_id", int],
"track": ["track", "target_id", int],
}
parts = value.lower().split(" ")
if parts[0].strip() not in config:
raise forms.ValidationError("Improper target")
conf = config[parts[0].strip()]
query = Q(target_content_type__model=conf[0])
if len(parts) > 1:
_, lookup_field, validator = conf
try:
lookup_value = validator(parts[1].strip())
except TypeError:
raise forms.ValidationError("Imparsable target id")
return query & Q(**{lookup_field: lookup_value})
return query
class MutationFilter(filters.FilterSet):
is_approved = NullBooleanFilter("is_approved")
q = fields.SmartSearchFilter(
@ -116,6 +141,7 @@ class MutationFilter(filters.FilterSet):
filter_fields={
"domain": {"to": "created_by__domain__name__iexact"},
"is_approved": get_null_boolean_filter("is_approved"),
"target": {"handler": filter_target},
"is_applied": {"to": "is_applied"},
},
)

View file

@ -77,12 +77,15 @@ class SearchConfig:
def clean(self, query):
tokens = parse_query(query)
cleaned_data = {}
cleaned_data["types"] = self.clean_types(filter_tokens(tokens, ["is"]))
cleaned_data["search_query"] = self.clean_search_query(
filter_tokens(tokens, [None, "in"])
filter_tokens(tokens, [None, "in"] + list(self.search_fields.keys()))
)
unhandled_tokens = [t for t in tokens if t["key"] not in [None, "is", "in"]]
unhandled_tokens = [
t
for t in tokens
if t["key"] not in [None, "is", "in"] + list(self.search_fields.keys())
]
cleaned_data["filter_query"] = self.clean_filter_query(unhandled_tokens)
return cleaned_data
@ -95,8 +98,33 @@ class SearchConfig:
} or set(self.search_fields.keys())
fields_subset = set(self.search_fields.keys()) & fields_subset
to_fields = [self.search_fields[k]["to"] for k in fields_subset]
specific_field_query = None
for token in tokens:
if token["key"] not in self.search_fields:
continue
to = self.search_fields[token["key"]]["to"]
try:
field = token["field"]
value = field.clean(token["value"])
except KeyError:
# no cleaning to apply
value = token["value"]
q = Q(**{"{}__icontains".format(to): value})
if not specific_field_query:
specific_field_query = q
else:
specific_field_query &= q
query_string = " ".join([t["value"] for t in filter_tokens(tokens, [None])])
return get_query(query_string, sorted(to_fields))
unhandled_tokens_query = get_query(query_string, sorted(to_fields))
if specific_field_query and unhandled_tokens_query:
return unhandled_tokens_query & specific_field_query
elif specific_field_query:
return specific_field_query
elif unhandled_tokens_query:
return unhandled_tokens_query
return None
def clean_filter_query(self, tokens):
if not self.filter_fields or not tokens:

View file

@ -36,6 +36,7 @@ class MutationViewSet(
lookup_field = "uuid"
queryset = (
models.Mutation.objects.all()
.exclude(target_id=None)
.order_by("-creation_date")
.select_related("created_by", "approved_by")
.prefetch_related("target")