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

访问Django路由/domains/{domain}/{host}时出现DetailView参数错误

解决Django DetailView报错:Generic detail view must be called with either an object pk or a slug

这个报错的原因很明确:Django的DetailView默认会期望从URL中拿到pk或者slug参数,用来自动定位单个模型对象,但你的URL里用的是domain和host两个自定义参数,而且你的get_queryset写法也不符合要求——它应该返回一个QuerySet,但你直接返回了单个对象,这就导致DetailView的内部逻辑混乱了。

下面是具体的修复方案:

1. 重写get_object方法(推荐方式)

因为我们需要通过domain和host两个参数来定位Host对象,直接重写get_object方法来手动查询是最清晰的方式,替换掉你原来的get_queryset方法:

# views.py
from django.http import Http404
from django.views.generic import DetailView
from .models import Host

class HostDetailPageView(DetailView):
    template_name = 'hosts/hostdetail.html'
    model = Host

    def get_object(self, queryset=None):
        # 从URL的kwargs中获取参数
        domain_name = self.kwargs.get('domain')
        host_name = self.kwargs.get('host')
        
        # 检查参数是否存在
        if not domain_name or not host_name:
            raise Http404("Missing required parameters")
        
        # 通过Domain的name和Host的name来查询对象
        # 这里假设你的Domain模型有一个`name`字段,和URL中的<str:domain>对应
        try:
            return Host.objects.get(domain__name=domain_name, name=host_name)
        except Host.DoesNotExist:
            raise Http404("Host does not exist")

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 如果需要添加额外的上下文数据,比如你之前提到的启用的域名列表,可以在这里添加
        # 示例:context['enabled_domains'] = Domain.objects.filter(is_enabled=True)
        return context

2. 为什么原来的写法有问题?

  • 你的get_queryset方法返回了filtered.first(),这是单个Host对象,但get_queryset的要求是返回QuerySet实例,DetailView会基于这个查询集再去用pk/slug筛选单个对象,返回单个对象会直接打破这个逻辑。
  • DetailView默认的对象查找逻辑只认pk或slug参数,你的URL里没有这两个参数,所以它不知道怎么定位对象,就抛出了那个错误。

3. 确认URL配置没问题

你的urls.py配置是正确的,参数名domain和host和视图中self.kwargs获取的名称一致,不需要修改:

# urls.py
urlpatterns = [
    path('domains/', DomainsPageView.as_view()),
    path('domains/<str:domain>', DomainHostsPageView.as_view()),
    path('domains/<str:domain>/<str:host>', HostDetailPageView.as_view()),
    path('', TemplateView.as_view(template_name="hosts/index.html"))
]

这样修改后,当访问/domains/{domain}/{host}时,DetailView会通过你重写的get_object方法,根据传入的域名和主机名找到对应的Host对象,就不会再抛出那个错误了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 21:03:11