使用JavaScript与Django模型过滤结果失效的问题求助
Let's get your city filtering working properly—let's break down the issues and fix them step by step:
1. Fix the Initial Session Setup Bug in JavaScript
First, your initial code has a typo that breaks setting the default city, which means your backend never gets a valid initial session value. Let's fix that and clean up the logic:
/* Ciudades */ if(localStorage.getItem("cities") == null){ $.ajax({ url: "/api/cities", method: "GET", dataType: "json", async: false }) .done(function(data, status){ localStorage.setObject("cities", data); }) .fail(function(data, status){ }); } $.each(localStorage.getObject("cities"), function(i, c){ template = '<li><a href="" class="header-city-option" data-id="' + c.id + '" data-name="' + c.name + '">' + c.name + '</a></li>'; $("#header-city-list").append(template); }); // Fix the typo and properly initialize default city if(localStorage.getItem("city-id") == null){ const firstCityLink = $("#header-city-list li:first-child a"); const defaultCityName = firstCityLink.data("name"); const defaultCityId = firstCityLink.data("id"); localStorage.setItem("city-name", defaultCityName); localStorage.setItem("city-id", defaultCityId); setCityInServer(defaultCityName, defaultCityId, false); } $("#header-city").html(localStorage.getItem("city-name") + ' <span class="caret"></span>'); $.each($(".city-filter-input") , function(i, v){ $(v).val(localStorage.getItem("city-id")); changeHomepageByCity(localStorage.getItem("city-name"), localStorage.getItem("city-id"), false); }); $(".header-city-option").click(function(ev){ ev.preventDefault(); var city = $(this).data("name"); var id = $(this).data("id"); localStorage.setItem("city-name", city); localStorage.setItem("city-id", id); $("#header-city").html(city + ' <span class="caret"></span>'); $.each( $(".city-filter-input") , function(i, v){ $(v).val(id); }); setCityInServer(city, id, true); }); function changeHomepageByCity(city, id, isClicked){ changeBackground(city); changeText(city); setCityInServer(city, id, isClicked); } function changeBackground(city){ var urlBackground; switch(city){ case "Manchester": urlBackground = "/static/img/fondo_main.jpg"; break; case "Liverpool": urlBackground = "/static/img/liverpool_background.jpg"; break; } $("#main").css("background-image", "url(" + urlBackground + ")"); } function changeText(city){ switch(city){ case "Manchester": $("#main h2").html("Live the languages with Milingual in Manchester"); $("#main p").html("We organize language conversation groups in the best venues in Manchester"); break; case "Liverpool": $("#main h2").html("Live the languages with Milingual in Liverpool"); $("#main p").html("We organize language conversation groups in the best venues in Liverpool"); break; } } function setCityInServer(city, id, isClicked){ var token = $("input[name*='csrfmiddlewaretoken']")[0].value; $.ajax({ type: "POST", url: "set-city-session", data: { cityName: city, cityId: id, csrfmiddlewaretoken: getCookie('csrftoken') }, success: function(){ if(isClicked) location.reload(); } }); }
The key fixes here:
- Corrected the typo
li:first-childa atoli:first-child a - Properly defined and passed the default city values to
setCityInServer - Removed the redundant
location.reload()call before the AJAX request
2. Add Session Fallback & Implement City Filtering in Django Views
Your main issue with the KeyError is that you're trying to access session values that might not exist yet. Use request.session.get() to safely retrieve values with defaults, then apply the city filter to your queries:
def IndexPage(request): # Get city from session, use a default if it doesn't exist (e.g., Manchester or first city in DB) default_city = City.objects.first() # Fallback to first city in your database city_name = request.session.get('city-name', default_city.name) city_id = request.session.get('city-id', default_city.id) # Filter venues to only the current city venues = ProfileVenue.objects.filter(city__name=city_name) # Optimize occurrence query to avoid N+1 database hits oc_list = Occurrence.objects.filter( date__gte=timezone.now(), event__location__in=venues ).select_related('event__location')[:3] # Filter teachers to the current city teachers_list = ProfileTeacher.objects.filter( published=True, city__name=city_name )[:3] languages = Language.objects.all() levels = LanguageLevel.objects.all() events = EventType.objects.all() context = { 'venues_today': oc_list, 'teachers': teachers_list, 'languages': languages, 'levels': levels, 'events': events } return render(request, "index.html", context) def SetCitySession(request): if request.method == "POST": # Safely set session values request.session['city-name'] = request.POST.get('cityName', '') request.session['city-id'] = request.POST.get('cityId', '') return JsonResponse({}) def GetCitySession(request): if request.method == "GET": default_city = City.objects.first() # Return fallback values if session is empty cityName = request.session.get('city-name', default_city.name) cityId = request.session.get('city-id', default_city.id) context = { "cityName": cityName, "cityId": cityId } return JsonResponse(context)
Key improvements here:
- Used
request.session.get()to avoidKeyErrorwhen session values don't exist - Added a database fallback to the first city in your
Citymodel for robustness - Optimized queries to avoid looping and N+1 database requests
- Applied city filters to both venues and teachers
3. Verify URL Routing
Make sure your set-city-session endpoint is correctly mapped in urls.py:
from django.urls import path from . import views urlpatterns = [ path('', views.IndexPage, name='index'), path('set-city-session/', views.SetCitySession, name='set-city-session'), path('get-city-session/', views.GetCitySession, name='get-city-session'), # Add other URLs as needed ]
How It Works Now
- On first load: The frontend grabs the first city from your API, sets it in localStorage, and sends it to the backend to store in the session. The view uses this city to filter all data.
- When a user selects a city: The frontend updates localStorage, sends the new city to the backend to update the session, then reloads the page. The view now uses the new city to filter results.
- On page refresh: The frontend pulls the city from localStorage, and the view pulls it from the session—keeping everything in sync.
内容的提问来源于stack exchange,提问作者fmakawa
相关产品推荐
相关产品推荐

