Django报错:Generic detail view需在URLconf传入pk或slug求助
解决Django DetailView URL关联错误:"Generic detail view must be called with either an object pk or a slug"
问题根源
Django的DetailView默认要求URL中传入对象的pk或slug参数定位单个对象,但你的视图是通过location_slug和date组合筛选数据,仅重写get_queryset无法覆盖DetailView的默认对象查找逻辑,因此触发错误。
修复步骤
1. 修正URL中的日期转换器
在urls.py中,将<date>改为<date:date>,让Django自动将URL中的日期字符串转换为date对象:
# urls.py urlpatterns = [ path("<slug:location_slug>/<date:date>/", DailyForecastDetailView.as_view(), name="daily_forecast_detail"), path("<slug:location_slug>/", DailyForecastTodayView.as_view(), name="daily_forecast_today"), path("<slug:location_slug>/<date:date>/<int:hour>/", HourlyForecastDetailView.as_view(), name="hourly_forecast_detail"), ]
2. 重写DetailView的get_object方法
替换原来的get_queryset为get_object,直接返回筛选后的单个对象:
修改DailyForecastDetailView
# views.py class DailyForecastDetailView(DetailView): model = DailyForecast template_name = "forecast/daily_forecast_detail.html" context_object_name = "forecast" def get_object(self, queryset=None): location_slug = self.kwargs["location_slug"] target_date = self.kwargs["date"] location = get_object_or_404(Location, slug=location_slug) return get_object_or_404(DailyForecast, location=location, date=target_date)
修改DailyForecastTodayView
# views.py class DailyForecastTodayView(DetailView): model = DailyForecast template_name = "forecast/daily_forecast_detail.html" context_object_name = "forecast" def get_object(self, queryset=None): location_slug = self.kwargs["location_slug"] location = get_object_or_404(Location, slug=location_slug) return get_object_or_404(DailyForecast, location=location, date=date.today())
修正HourlyForecastDetailView的筛选条件
模型中没有hour字段,需通过time__hour筛选小时,同时重写get_object:
# views.py class HourlyForecastDetailView(DetailView): model = HourlyForecast template_name = "forecast/hourly_forecast_detail.html" context_object_name = "forecast" def get_object(self, queryset=None): location_slug = self.kwargs["location_slug"] target_date = self.kwargs["date"] target_hour = self.kwargs["hour"] location = get_object_or_404(Location, slug=location_slug) # 筛选指定日期和小时的逐小时预报 return get_object_or_404( HourlyForecast, location=location, time__date=target_date, time__hour=target_hour )
3. 可选:为DailyForecast添加唯一约束
确保同一个地点同一天只有一条预报数据,避免get_object_or_404返回多个对象:
# models.py class DailyForecast(Forecast): # ... 原有字段 ... class Meta: verbose_name_plural = "daily forecasts" unique_together = ("location", "date") # 添加唯一约束
验证
重新启动服务后,访问以下URL即可正常显示:
- 带日期:
http://127.0.0.1:8000/forecast/narnia/2023-03-26/ - 不带日期(显示今日预报):
http://127.0.0.1:8000/forecast/narnia/
内容的提问来源于stack exchange,提问作者user2610407
相关产品推荐
相关产品推荐

