Django开发校园停车场查询网站,如何实现含缩写的校园名输入不敏感匹配
代码改造方案
现存核心问题
- 原视图用
name__iexact做不区分大小写的精确匹配,仅能识别和校园正式名称完全一致(仅大小写有差异)的输入,完全不支持缩写、带标点的缩写、简称、俗称类的输入匹配 - 视图存在逻辑bug:渲染返回的代码块被误写在停车场遍历的for循环内部,处理完第一个停车场就会直接返回,无法加载全部车位数据
- 无输入标准化处理流程:用户输入里的多余空格、缩写自带的分隔点、全半角字符差异,都会直接导致匹配失败
具体改造步骤
1. 补全别名匹配的数据基础
需要给Campus模型新增别名存储字段,提前录入每个校园对应的所有可能被用户输入的缩写、俗称、别名,避免模糊匹配导致的跨校区误判:
# models.py 新增字段示例 from django.db import models class Campus(models.Model): name = models.CharField(max_length=100, verbose_name="校园正式名称") # 存储所有可匹配的别名、缩写 alias_list = models.JSONField(default=list, verbose_name="匹配别名", help_text="例如DCU Alpha的可匹配项可填:['DCU', 'D.C.U.', 'DCU 阿尔法', '都柏林城市大学Alpha校区']")
2. 增加输入标准化处理逻辑
在拿到用户的输入后,先做统一格式清洗,消除无意义的格式差异:
- 全角字符转半角
- 移除输入中无意义的标点(比如缩写里的分隔点、特殊符号)
- 把连续的多个空格合并为单个空格
- 统一转成大写格式,消除大小写差异
对应的处理函数可以写在视图文件里:
import re def normalize_input(raw_str): if not raw_str: return "" # 全角括号转半角 normalized = raw_str.translate(str.maketrans('()', '()')) # 去掉所有非文字、数字、空格的标点 normalized = re.sub(r'[^\w\s]', '', normalized).strip() # 合并连续空格 normalized = re.sub(r'\s+', ' ', normalized) return normalized.upper()
这样不管用户输入d.c.u alpha、DCU Alpha、dcualpha,经过处理后都会变成统一的匹配格式。
3. 重构视图的匹配逻辑,修复原有bug
把原来的精确查找逻辑替换为「正式名称+别名」的双层匹配,同时修复之前的缩进bug,把返回渲染的代码移到遍历停车场的循环外面,改造后的views.py参考:
import requests from django.shortcuts import render from .models import Campus, Carpark # 输入标准化函数 def normalize_input(raw_str): if not raw_str: return "" normalized = raw_str.translate(str.maketrans('()', '()')) normalized = re.sub(r'[^\w\s]', '', normalized).strip() normalized = re.sub(r'\s+', ' ', normalized) return normalized.upper() def carparks(request): context = {} Base_URL = 'http://jfoster.pythonanywhere.com/carparks/' # 增加参数兜底,避免用户未传campus参数时触发报错 raw_campus_input = request.GET.get('campus', '') if not raw_campus_input: return render(request, "parkatdcu/carparks.html", context) # 对用户输入做标准化处理 normalized_input = normalize_input(raw_campus_input) matched_campus = None # 遍历所有校区做匹配(数据量较小时完全适用) for campus in Campus.objects.all(): # 对校区正式名称也做同样的标准化处理 campus_name_norm = normalize_input(campus.name) # 对每个存的别名做标准化处理 campus_alias_norm = [normalize_input(alias) for alias in campus.alias_list] # 命中正式名或任意别名即视为匹配成功 if normalized_input == campus_name_norm or normalized_input in campus_alias_norm: matched_campus = campus break # 未匹配到对应校区时直接返回空上下文 if not matched_campus: return render(request, "parkatdcu/carparks.html", context) # 获取匹配校区下的所有停车场 carparks = Carpark.objects.filter(campus_id=matched_campus) carpark_info = [] for carpark in carparks: URL = Base_URL + carpark.name r = requests.get(URL).json() spaces_available = r.get('spaces_available', '暂不可用') carpark_info.append({ 'name': carpark.name, 'spaces': carpark.spaces, 'disabled_spaces': carpark.disabled_spaces, 'spaces_available': spaces_available }) # 传给前端的校区名使用正式名称,不直接展示用户输入的内容 context['campus'] = matched_campus.name.title() context['carparks'] = carpark_info # 确保所有停车场数据处理完成后再返回渲染 return render(request, "parkatdcu/carparks.html", context)
4. 前端模板适配调整
原模板逻辑基本可复用,只需要把英文提示替换为中文适配内容即可,调整后的carparks.html参考:
<h2> {% if campus %} {{ campus }} {% else %} 未查询到对应校区 {% endif %} </h2> {% if campus %} {% if carparks %} <ul> {% for carpark in carparks %} <li>{{carpark.name}}:总车位 {{carpark.spaces}} 个,其中残疾人专用车位 {{carpark.disabled_spaces}} 个 <br>当前剩余可用车位:{{ carpark.spaces_available }} <br><br> </li> {% endfor %} </ul> {% else %} <p>该校区暂未录入停车场信息</p> {% endif %} {% endif %}
注意事项
- 不要直接用
name__contains这类模糊匹配逻辑识别缩写,极易出现跨校区误判(比如输入"DCU"时同时命中DCU Alpha、DCU Beta两个校区),必须靠提前录入的别名做精准匹配 - 如果校园数据量较大(上千条),可以给
alias_list字段建JSON索引,把循环匹配改成数据库原生查询,避免遍历全表带来的性能问题 - 输入标准化时不要过度清洗内容,比如不要移除名称里的空格,否则会提升误匹配概率
内容的提问来源于stack exchange,提问作者user14464799
相关产品推荐
相关产品推荐

