You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中基于表单字段值动态拉取API数据的医疗设施搜索问题

解决方案:Django医疗设施搜索的动态结果过滤

嘿,我之前在Django项目里做过类似的医疗设施层级搜索功能,刚好能给你一些实用的解决方案!根据你的需求,我们可以分两种场景来实现「仅拉取相关结果」的功能——层级联动过滤(国家→地区→城市→医疗设施)和实时关键词搜索过滤,下面分别详细说明:

一、层级联动过滤(适合按地理层级逐步缩小范围)

这种方案适合用户通过选择上级选项(比如国家),自动加载对应的下级选项(比如该国家的地区),避免一次性加载全部数据,提升页面性能和用户体验。

1. 后端视图编写

首先创建几个API视图,用于根据父级ID返回对应的子级数据:

from django.http import JsonResponse
from django.views.decorators.cache import cache_page
from .models import Country, Region, City, MedicalFacility

# 缓存地区数据(24小时,因为地理数据不会频繁更新)
@cache_page(60 * 60 * 24)
def get_regions(request):
    country_id = request.GET.get("country_id")
    if not country_id:
        return JsonResponse([], safe=False)
    
    # 过滤对应国家的地区,返回ID和名称
    regions = Region.objects.filter(country_id=country_id).values("id", "name")
    return JsonResponse(list(regions), safe=False)

# 同理编写获取城市的视图
@cache_page(60 * 60 * 24)
def get_cities(request):
    region_id = request.GET.get("region_id")
    if not region_id:
        return JsonResponse([], safe=False)
    
    cities = City.objects.filter(region_id=region_id).values("id", "name")
    return JsonResponse(list(cities), safe=False)

# 获取对应城市的医疗设施
def get_facilities(request):
    city_id = request.GET.get("city_id")
    if not city_id:
        return JsonResponse([], safe=False)
    
    facilities = MedicalFacility.objects.filter(city_id=city_id).values("id", "name", "address")
    return JsonResponse(list(facilities), safe=False)

然后在urls.py中配置这些API路由:

from django.urls import path
from . import views

urlpatterns = [
    # 其他路由...
    path("api/get-regions/", views.get_regions, name="get_regions"),
    path("api/get-cities/", views.get_cities, name="get_cities"),
    path("api/get-facilities/", views.get_facilities, name="get_facilities"),
]

2. 前端交互实现

在模板中添加选择框,并通过JavaScript监听选择事件,发送AJAX请求更新下级选项:

<form method="get" action="{% url 'search_results' %}">
    <div class="form-group">
        <label>国家:</label>
        <select id="country-select" name="country">
            <option value="">请选择国家</option>
            {% for country in countries %}
                <option value="{{ country.id }}">{{ country.name }}</option>
            {% endfor %}
        </select>
    </div>

    <div class="form-group">
        <label>地区:</label>
        <select id="region-select" name="region" disabled>
            <option value="">请先选择国家</option>
        </select>
    </div>

    <div class="form-group">
        <label>城市:</label>
        <select id="city-select" name="city" disabled>
            <option value="">请先选择地区</option>
        </select>
    </div>

    <div class="form-group">
        <label>医疗设施:</label>
        <select id="facility-select" name="facility" disabled>
            <option value="">请先选择城市</option>
        </select>
    </div>

    <button type="submit" class="btn btn-primary">搜索</button>
</form>

<script>
document.addEventListener('DOMContentLoaded', () => {
    const countrySel = document.getElementById('country-select');
    const regionSel = document.getElementById('region-select');
    const citySel = document.getElementById('city-select');
    const facilitySel = document.getElementById('facility-select');

    // 国家选择变化时更新地区
    countrySel.addEventListener('change', async () => {
        const countryId = countrySel.value;
        regionSel.disabled = !countryId;
        citySel.disabled = true;
        facilitySel.disabled = true;

        // 清空下级选项
        regionSel.innerHTML = '<option value="">请选择地区</option>';
        citySel.innerHTML = '<option value="">请先选择地区</option>';
        facilitySel.innerHTML = '<option value="">请先选择城市</option>';

        if (!countryId) return;

        try {
            const response = await fetch(`/api/get-regions/?country_id=${countryId}`);
            const regions = await response.json();
            
            let options = '<option value="">请选择地区</option>';
            regions.forEach(region => {
                options += `<option value="${region.id}">${region.name}</option>`;
            });
            regionSel.innerHTML = options;
        } catch (err) {
            console.error('加载地区失败:', err);
        }
    });

    // 地区选择变化时更新城市
    regionSel.addEventListener('change', async () => {
        const regionId = regionSel.value;
        citySel.disabled = !regionId;
        facilitySel.disabled = true;

        citySel.innerHTML = '<option value="">请选择城市</option>';
        facilitySel.innerHTML = '<option value="">请先选择城市</option>';

        if (!regionId) return;

        try {
            const response = await fetch(`/api/get-cities/?region_id=${regionId}`);
            const cities = await response.json();
            
            let options = '<option value="">请选择城市</option>';
            cities.forEach(city => {
                options += `<option value="${city.id}">${city.name}</option>`;
            });
            citySel.innerHTML = options;
        } catch (err) {
            console.error('加载城市失败:', err);
        }
    });

    // 城市选择变化时更新医疗设施
    citySel.addEventListener('change', async () => {
        const cityId = citySel.value;
        facilitySel.disabled = !cityId;

        facilitySel.innerHTML = '<option value="">请选择医疗设施</option>';

        if (!cityId) return;

        try {
            const response = await fetch(`/api/get-facilities/?city_id=${cityId}`);
            const facilities = await response.json();
            
            let options = '<option value="">请选择医疗设施</option>';
            facilities.forEach(facility => {
                options += `<option value="${facility.id}">${facility.name} - ${facility.address}</option>`;
            });
            facilitySel.innerHTML = options;
        } catch (err) {
            console.error('加载医疗设施失败:', err);
        }
    });
});
</script>

二、实时关键词搜索过滤(适合用户直接输入关键词缩小范围)

如果需要支持用户输入关键词实时过滤医疗设施,可以结合层级过滤和关键词搜索,实现更灵活的搜索体验。

1. 后端搜索视图

from django.http import JsonResponse
from .models import MedicalFacility

def search_facilities(request):
    # 获取前端传入的参数
    query = request.GET.get("q", "").strip()
    country_id = request.GET.get("country_id", "")
    region_id = request.GET.get("region_id", "")
    city_id = request.GET.get("city_id", "")

    # 基础查询集
    facilities = MedicalFacility.objects.all()

    # 按关键词过滤(模糊匹配名称或地址)
    if query:
        facilities = facilities.filter(
            name__icontains=query
        ) | facilities.filter(
            address__icontains=query
        )
    
    # 按地理层级过滤
    if country_id:
        facilities = facilities.filter(city__region__country_id=country_id)
    if region_id:
        facilities = facilities.filter(city__region_id=region_id)
    if city_id:
        facilities = facilities.filter(city_id=city_id)

    # 返回结果(限制数量避免数据过多)
    return JsonResponse(list(facilities.values("id", "name", "address")[:50]), safe=False)

在urls.py添加路由:

path("api/search-facilities/", views.search_facilities, name="search_facilities"),

2. 前端搜索交互

在模板中添加搜索框,并监听输入事件:

<div class="form-group">
    <label>搜索医疗设施:</label>
    <input type="text" id="search-input" placeholder="输入名称或地址搜索..." class="form-control">
</div>

<script>
const searchInput = document.getElementById('search-input');
const facilitySel = document.getElementById('facility-select');

searchInput.addEventListener('input', async () => {
    const query = searchInput.value;
    const countryId = countrySel.value;
    const regionId = regionSel.value;
    const cityId = citySel.value;

    // 构建请求URL
    let urlParams = new URLSearchParams();
    if (query) urlParams.append('q', query);
    if (countryId) urlParams.append('country_id', countryId);
    if (regionId) urlParams.append('region_id', regionId);
    if (cityId) urlParams.append('city_id', cityId);

    try {
        const response = await fetch(`/api/search-facilities/?${urlParams.toString()}`);
        const facilities = await response.json();
        
        let options = '<option value="">请选择医疗设施</option>';
        facilities.forEach(facility => {
            options += `<option value="${facility.id}">${facility.name} - ${facility.address}</option>`;
        });
        facilitySel.innerHTML = options;
    } catch (err) {
        console.error('搜索失败:', err);
    }
});
</script>

三、优化建议

  • 缓存优化:对于地理数据(国家、地区、城市),使用Django的缓存装饰器@cache_page减少数据库查询,提升响应速度。
  • 前端体验:添加加载动画(比如请求时在选择框旁显示加载图标),避免用户重复操作。
  • 参数验证:后端视图中可以添加参数类型验证(比如检查country_id是否为整数),避免非法请求。
  • 分页处理:如果医疗设施数量极大,在搜索视图中添加分页,避免一次性返回过多数据。

内容的提问来源于stack exchange,提问作者kbdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:19:31