如何为Django业务目录实现分类+城市/地区层级查询页面
Django业务目录层级查询页面解决方案
问题描述
我开发了一个Django业务目录系统,已完成分类页面(如abc.com/category/manufacturing/)的开发,但在实现分类+城市(如abc.com/category/manufacturing/london/)、分类+城市+地区(如abc.com/category/manufacturing/london/southwark/)的层级查询页面时遇到困难,尝试多种方法均失败。以下是我的代码文件:
现有代码
models.py
from django.db import models from django.urls import reverse from tinymce import models as tinymce_models # Create your models here. class City(models.Model): city = models.CharField(max_length=50) slug = models.SlugField() def __str__(self): return str(self.city) class District(models.Model): district = models.CharField(max_length=50) slug = models.SlugField() city = models.ForeignKey(City, on_delete=models.CASCADE) def __str__(self): return str(self.district) class FirmaCategory(models.Model): title = models.CharField(max_length=255) slug = models.SlugField() class Meta: verbose_name_plural = 'Firma Kategorileri' def __str__(self): return str(self.title) class Firma(models.Model): category = models.ForeignKey(FirmaCategory, related_name="Firma", on_delete=models.CASCADE) title = models.CharField(max_length=255) slug = models.SlugField() adres = tinymce_models.HTMLField() tel = tinymce_models.HTMLField() website = tinymce_models.HTMLField() email = tinymce_models.HTMLField() intro = tinymce_models.HTMLField() body = tinymce_models.HTMLField() city = models.ForeignKey(City,related_name="FirmaCategory" ,on_delete=models.CASCADE) district = models.ForeignKey(District,related_name="FirmaCategory", on_delete=models.CASCADE) date_added = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = 'Firmalar' def __str__(self): return str(self.title) def get_absolute_url(self): return reverse('firma-frontpage')
views.py
from django.db.models import Q from django.shortcuts import render from .models import Firma, FirmaCategory, City, District from django.utils.html import format_html from django.views.generic import CreateView from .forms import FirmaForm # Create your views here. def firmaana(request): firmalar = Firma.objects.all() context = { 'firmalar': firmalar } return render(request, 'firma/firma-frontpage.html', context) def firmadetail(request, slug): firmax = Firma.objects.get(slug=slug) context = { 'firmax': firmax, } return render(request, 'firma/firma-detail.html', context) def firmacategory(request, slug): firmacategory = FirmaCategory.objects.get(slug=slug) context = { 'firmacategory': firmacategory } return render(request, 'firma/firma-category.html', context)
urls.py
urlpatterns = [ path('kategory/city/<city>/', views.list_businesses_by_city, name='firmail'), path("", views.firmaana, name="firma-frontpage"), path("<slug:slug>/", views.firmadetail, name="firma-detail"), path("kategory/<slug:slug>/", views.firmacategory, name="firma-category"), path("1/add-firma/", FirmaEkle.as_view(), name="firma-ekle"), path('tinymce/', include('tinymce.urls')), ]
解决方案
1. 调整URL配置
修改urls.py,添加层级路由并调整顺序(更具体的路由必须放在前面,避免被通用路由匹配):
urlpatterns = [ path("", views.firmaana, name="firma-frontpage"), # 分类+城市+地区路由 path("kategory/<slug:category_slug>/<slug:city_slug>/<slug:district_slug>/", views.firma_category_city_district, name="firma-category-city-district"), # 分类+城市路由 path("kategory/<slug:category_slug>/<slug:city_slug>/", views.firma_category_city, name="firma-category-city"), # 基础分类路由 path("kategory/<slug:slug>/", views.firmacategory, name="firma-category"), path("<slug:slug>/", views.firmadetail, name="firma-detail"), path("1/add-firma/", FirmaEkle.as_view(), name="firma-ekle"), path('tinymce/', include('tinymce.urls')), # 移除旧的单一城市路由 # path('kategory/city/<city>/', views.list_businesses_by_city, name='firmail'), ]
2. 编写层级查询视图
在views.py中添加两个新视图,分别处理不同层级的筛选逻辑:
def firma_category_city(request, category_slug, city_slug): # 获取分类和城市实例 category = FirmaCategory.objects.get(slug=category_slug) city = City.objects.get(slug=city_slug) # 筛选该分类+城市下的企业,用select_related减少数据库查询 firmalar = Firma.objects.filter(category=category, city=city).select_related('category', 'city', 'district') # 获取当前城市的所有地区,用于页面导航 districts = District.objects.filter(city=city) context = { 'category': category, 'city': city, 'firmalar': firmalar, 'districts': districts } return render(request, 'firma/firma-category-city.html', context) def firma_category_city_district(request, category_slug, city_slug, district_slug): category = FirmaCategory.objects.get(slug=category_slug) city = City.objects.get(slug=city_slug) district = District.objects.get(slug=district_slug, city=city) # 筛选分类+城市+地区下的企业 firmalar = Firma.objects.filter(category=category, city=city, district=district).select_related('category', 'city', 'district') context = { 'category': category, 'city': city, 'district': district, 'firmalar': firmalar } return render(request, 'firma/firma-category-city-district.html', context)
3. 模板页面适配
创建对应层级的模板文件(如firma-category-city.html和firma-category-city-district.html),展示筛选结果和层级导航。例如在分类页面中添加城市跳转链接:
<!-- firma-category.html 示例片段 --> <h1>{{ firmacategory.title }}</h1> <h3>按城市筛选:</h3> <ul> {% for city in City.objects.all %} <li><a href="{% url 'firma-category-city' firmacategory.slug city.slug %}">{{ city.city }}</a></li> {% endfor %} </ul> <h3>该分类下的所有企业:</h3> <ul> {% for firma in firmacategory.Firma.all %} <li><a href="{% url 'firma-detail' firma.slug %}">{{ firma.title }}</a></li> {% endfor %} </ul>
4. 模型关联优化(可选)
给Firma模型的外键设置更清晰的反向关联名称,方便后续查询:
class Firma(models.Model): # ... 其他字段 ... city = models.ForeignKey(City, related_name="firms", on_delete=models.CASCADE) district = models.ForeignKey(District, related_name="firms_in_district", on_delete=models.CASCADE)
关键注意事项
- 路由顺序必须严格:层级更细的路由要放在基础路由前面,否则会被提前匹配导致404。
- 使用
select_related优化查询性能,避免N+1查询问题。 - 给
slug字段添加unique=True约束(如slug = models.SlugField(unique=True)),确保每个分类、城市、地区的slug唯一,避免查询时出现多个匹配实例的错误。
内容的提问来源于stack exchange,提问作者Prusa
相关产品推荐
相关产品推荐

