前端适配
This commit is contained in:
parent
79b09c17f9
commit
bf9d136112
|
|
@ -140,19 +140,18 @@ async def suggest_autocomplete(
|
||||||
text_field: str = "text",
|
text_field: str = "text",
|
||||||
hira_field: str = "hiragana",
|
hira_field: str = "hiragana",
|
||||||
freq_field: str = "freq",
|
freq_field: str = "freq",
|
||||||
english_field: str = "eng_explanation",
|
|
||||||
limit: int = 10,
|
limit: int = 10,
|
||||||
) -> List[Dict[str, str]]:
|
) -> List[Dict[str, str]]:
|
||||||
"""
|
"""
|
||||||
通用自动补全建议接口(增强版):
|
通用自动补全建议接口:
|
||||||
- 法语: 按 search_text / text 搜索,同时反查 DefinitionFr 的英文释义
|
- 法语: 按 search_text / text 搜索 + 反查 DefinitionFr 英/中释义
|
||||||
- 日语: 先按原文 text 匹配,再按假名 search_text 匹配
|
- 日语: 先按原文 text 匹配,再按假名匹配 + 反查 DefinitionJp 中文释义
|
||||||
统一返回结构:
|
统一返回结构:
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"word": "étudier",
|
"word": "étudier",
|
||||||
"hiragana": None,
|
"hiragana": None,
|
||||||
"meanings": [],
|
"meanings": ["学习", "研究"],
|
||||||
"english": ["to study", "to learn"]
|
"english": ["to study", "to learn"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -161,19 +160,25 @@ async def suggest_autocomplete(
|
||||||
if not keyword:
|
if not keyword:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# ========== 法语 ==========
|
# ========== 法语分支 ==========
|
||||||
if dict_lang == "fr":
|
if dict_lang == "fr":
|
||||||
start_condition = Q(**{f"{search_field}__istartswith": keyword}) | Q(**{f"{text_field}__istartswith": keyword})
|
start_condition = (
|
||||||
contain_condition = Q(**{f"{search_field}__icontains": keyword}) | Q(**{f"{text_field}__icontains": keyword})
|
Q(**{f"{search_field}__istartswith": keyword})
|
||||||
|
| Q(**{f"{text_field}__istartswith": keyword})
|
||||||
|
)
|
||||||
|
contain_condition = (
|
||||||
|
Q(**{f"{search_field}__icontains": keyword})
|
||||||
|
| Q(**{f"{text_field}__icontains": keyword})
|
||||||
|
)
|
||||||
value_fields = ["id", text_field, freq_field, search_field]
|
value_fields = ["id", text_field, freq_field, search_field]
|
||||||
|
|
||||||
# ========== 日语 ==========
|
# ========== 日语分支 ==========
|
||||||
elif dict_lang == "jp":
|
elif dict_lang == "jp":
|
||||||
kana_word = all_in_kana(keyword)
|
kana_word = all_in_kana(keyword)
|
||||||
start_condition = Q(**{f"{text_field}__istartswith": keyword})
|
start_condition = Q(**{f"{text_field}__startswith": keyword})
|
||||||
contain_condition = Q(**{f"{text_field}__icontains": keyword})
|
contain_condition = Q(**{f"{text_field}__icontains": keyword})
|
||||||
|
|
||||||
kana_start = Q(**{f"{hira_field}__istartswith": kana_word})
|
kana_start = Q(**{f"{hira_field}__startswith": kana_word})
|
||||||
kana_contain = Q(**{f"{hira_field}__icontains": kana_word})
|
kana_contain = Q(**{f"{hira_field}__icontains": kana_word})
|
||||||
|
|
||||||
start_condition |= kana_start
|
start_condition |= kana_start
|
||||||
|
|
@ -183,7 +188,7 @@ async def suggest_autocomplete(
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# ✅ 1. 开头匹配
|
# ✅ 获取匹配单词
|
||||||
start_matches = await (
|
start_matches = await (
|
||||||
model.filter(start_condition)
|
model.filter(start_condition)
|
||||||
.order_by(f"-{freq_field}", "id")
|
.order_by(f"-{freq_field}", "id")
|
||||||
|
|
@ -191,7 +196,6 @@ async def suggest_autocomplete(
|
||||||
.values(*value_fields)
|
.values(*value_fields)
|
||||||
)
|
)
|
||||||
|
|
||||||
# ✅ 2. 包含匹配
|
|
||||||
contain_matches = await (
|
contain_matches = await (
|
||||||
model.filter(contain_condition & ~start_condition)
|
model.filter(contain_condition & ~start_condition)
|
||||||
.order_by(f"-{freq_field}", "id")
|
.order_by(f"-{freq_field}", "id")
|
||||||
|
|
@ -199,33 +203,55 @@ async def suggest_autocomplete(
|
||||||
.values(*value_fields)
|
.values(*value_fields)
|
||||||
)
|
)
|
||||||
|
|
||||||
# ✅ 3. 合并去重
|
|
||||||
results = []
|
results = []
|
||||||
seen_ids = set()
|
seen_ids = set()
|
||||||
for row in start_matches + contain_matches:
|
for row in start_matches + contain_matches:
|
||||||
if row["id"] in seen_ids:
|
if row["id"] not in seen_ids:
|
||||||
continue
|
|
||||||
seen_ids.add(row["id"])
|
seen_ids.add(row["id"])
|
||||||
|
results.append({
|
||||||
result = {
|
"id": row["id"],
|
||||||
"word": row[text_field],
|
"word": row[text_field],
|
||||||
"hiragana": row.get(hira_field) if dict_lang == "jp" else None,
|
"hiragana": row.get(hira_field) if dict_lang == "jp" else None,
|
||||||
"meanings": [],
|
"meanings": [],
|
||||||
"english": [],
|
"english": [],
|
||||||
}
|
})
|
||||||
|
|
||||||
# ✅ 若为法语,则反查 DefinitionFr 的英文释义
|
# ✅ 批量反查 Definition 表,防止 N+1 查询
|
||||||
if dict_lang == "fr":
|
if dict_lang == "fr":
|
||||||
# 获取关联的 definitions
|
from app.models import DefinitionFr # 避免循环导入
|
||||||
word_obj = await model.get(id=row["id"]).prefetch_related("definitions")
|
word_ids = [r["id"] for r in results]
|
||||||
english_list = [
|
defs = await DefinitionFr.filter(word_id__in=word_ids).values("word_id", "meaning", "eng_explanation")
|
||||||
d.eng_explanation.strip()
|
|
||||||
for d in word_obj.definitions
|
|
||||||
if d.eng_explanation and d.eng_explanation.strip()
|
|
||||||
]
|
|
||||||
result["english"] = list(set(english_list))
|
|
||||||
|
|
||||||
results.append(result)
|
meaning_map: Dict[int, Dict[str, List[str]]] = {}
|
||||||
|
for d in defs:
|
||||||
|
meaning_map.setdefault(d["word_id"], {"meanings": [], "english": []})
|
||||||
|
if d["meaning"]:
|
||||||
|
meaning_map[d["word_id"]]["meanings"].append(d["meaning"].strip())
|
||||||
|
if d["eng_explanation"]:
|
||||||
|
meaning_map[d["word_id"]]["english"].append(d["eng_explanation"].strip())
|
||||||
|
|
||||||
|
for r in results:
|
||||||
|
if r["id"] in meaning_map:
|
||||||
|
r["meanings"] = list(set(meaning_map[r["id"]]["meanings"]))
|
||||||
|
r["english"] = list(set(meaning_map[r["id"]]["english"]))
|
||||||
|
|
||||||
|
elif dict_lang == "jp":
|
||||||
|
from app.models import DefinitionJp
|
||||||
|
word_ids = [r["id"] for r in results]
|
||||||
|
defs = await DefinitionJp.filter(word_id__in=word_ids).values("word_id", "meaning")
|
||||||
|
|
||||||
|
meaning_map: Dict[int, List[str]] = {}
|
||||||
|
for d in defs:
|
||||||
|
if d["meaning"]:
|
||||||
|
meaning_map.setdefault(d["word_id"], []).append(d["meaning"].strip())
|
||||||
|
|
||||||
|
for r in results:
|
||||||
|
if r["id"] in meaning_map:
|
||||||
|
r["meanings"] = list(set(meaning_map[r["id"]]))
|
||||||
|
|
||||||
|
# ✅ 删除 id,只保留用户需要字段
|
||||||
|
for r in results:
|
||||||
|
r.pop("id", None)
|
||||||
|
|
||||||
return results[:limit]
|
return results[:limit]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue