refactor(main): search_tags JOINs fandom; matches on display CONCAT
Post-refactor tag.name is bare. Autocomplete needs to match the
display form (name + ' (' + fandom.name + ')') so users can still
find 'Ruby Rose (RWBY)' by typing 'rwby'. Switched to
contains_eager(Tag.fandom, alias=f) to eliminate the duplicate
join that caused a Postgres GROUP BY error in the no-query path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+31
-21
@@ -3,7 +3,7 @@
|
||||
from flask import Blueprint, render_template, flash, redirect, url_for, abort, send_from_directory, request, jsonify, current_app
|
||||
|
||||
from sqlalchemy import desc, func, text, extract, and_
|
||||
from sqlalchemy.orm import joinedload, aliased
|
||||
from sqlalchemy.orm import joinedload, aliased, contains_eager
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
|
||||
@@ -637,28 +637,41 @@ def search_tags():
|
||||
"""
|
||||
Search existing tags for autocomplete.
|
||||
Query params:
|
||||
- q: search query (matches tag name, case-insensitive)
|
||||
- q: search query (matches against display_name, case-insensitive)
|
||||
- limit: max results (default 10)
|
||||
- exclude_kind: comma-separated list of tag kinds to exclude (e.g., 'archive')
|
||||
- kind: filter to only include tags of this kind (e.g., 'series')
|
||||
- exclude_kind: comma-separated list of tag kinds to exclude
|
||||
- kind: filter to only include tags of this kind
|
||||
"""
|
||||
query = request.args.get('q', '').strip().lower()
|
||||
limit = request.args.get('limit', 10, type=int)
|
||||
exclude_kind = request.args.get('exclude_kind', '').strip()
|
||||
exclude_kinds = [k.strip() for k in exclude_kind.split(',') if k.strip()]
|
||||
include_kind = request.args.get('kind', '').strip()
|
||||
from sqlalchemy import case
|
||||
|
||||
query = request.args.get("q", "").strip().lower()
|
||||
limit = request.args.get("limit", 10, type=int)
|
||||
exclude_kind = request.args.get("exclude_kind", "").strip()
|
||||
exclude_kinds = [k.strip() for k in exclude_kind.split(",") if k.strip()]
|
||||
include_kind = request.args.get("kind", "").strip()
|
||||
|
||||
f = aliased(Tag)
|
||||
display_expr = case(
|
||||
(
|
||||
and_(Tag.kind == "character", Tag.fandom_id.isnot(None)),
|
||||
func.concat(Tag.name, " (", f.name, ")"),
|
||||
),
|
||||
else_=Tag.name,
|
||||
)
|
||||
|
||||
if not query:
|
||||
# Return most-used tags when no query
|
||||
base_query = (
|
||||
Tag.query
|
||||
.join(image_tags)
|
||||
.group_by(Tag.id)
|
||||
db.session.query(Tag)
|
||||
.outerjoin(f, f.id == Tag.fandom_id)
|
||||
.options(contains_eager(Tag.fandom, alias=f))
|
||||
)
|
||||
if exclude_kinds:
|
||||
base_query = base_query.filter(~Tag.kind.in_(exclude_kinds))
|
||||
if include_kind:
|
||||
base_query = base_query.filter(Tag.kind == include_kind)
|
||||
|
||||
if not query:
|
||||
# No query: most-used tags.
|
||||
base_query = base_query.join(image_tags, image_tags.c.tag_id == Tag.id).group_by(Tag.id, f.id)
|
||||
tags = (
|
||||
base_query
|
||||
.order_by(func.count(image_tags.c.image_id).desc())
|
||||
@@ -666,14 +679,10 @@ def search_tags():
|
||||
.all()
|
||||
)
|
||||
else:
|
||||
base_query = Tag.query.filter(Tag.name.ilike(f'%{query}%'))
|
||||
if exclude_kinds:
|
||||
base_query = base_query.filter(~Tag.kind.in_(exclude_kinds))
|
||||
if include_kind:
|
||||
base_query = base_query.filter(Tag.kind == include_kind)
|
||||
base_query = base_query.filter(display_expr.ilike(f"%{query}%"))
|
||||
tags = (
|
||||
base_query
|
||||
.order_by(Tag.name)
|
||||
.order_by(display_expr)
|
||||
.limit(limit)
|
||||
.all()
|
||||
)
|
||||
@@ -682,9 +691,10 @@ def search_tags():
|
||||
{
|
||||
"id": t.id,
|
||||
"name": t.name,
|
||||
"display_name": t.display_name,
|
||||
"kind": t.kind,
|
||||
"fandom_id": t.fandom_id if t.kind == "character" else None,
|
||||
"fandom_name": (t.fandom.name.split(":", 1)[1] if t.fandom else None) if t.kind == "character" else None
|
||||
"fandom_name": (t.fandom.name if t.fandom else None) if t.kind == "character" else None,
|
||||
}
|
||||
for t in tags
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user