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

Django整合DetailView与FormView报错:'TestDetails'无'object'属性

Django中DetailView与FormView组合使用时的AttributeError问题

点击考试表单提交按钮后,Django抛出错误:
AttributeError: 'TestDetails' object has no attribute 'object'

视图代码:

class TestDetails(DetailView, FormView):
    model = Test
    form_class = QuestionForm
    context_object_name = 'test'
    pk_url_kwarg = 'test_id'
    template_name = 'app/views/test_details.html'

    def get_context_data(self, **kwargs):
        test_id = self.kwargs.get('test_id')
        context = super().get_context_data(**kwargs)
        context['title'] = f'Тест - {test_id}'
        context['questions'] = Question.objects.filter(test_id=test_id)
        return context

    def form_valid(self, form):
        print(form.cleaned_data)
        return super().form_valid(form)

    def form_invalid(self, form):
        print(form.cleaned_data)
        return super().form_invalid(form)

完整回溯信息:

Internal Server Error: /tests/1
Traceback (most recent call last):
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\.venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\.venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\.venv\lib\site-packages\django\views\generic\base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\.venv\lib\site-packages\django\views\generic\base.py", line 143, in dispatch
    return handler(request, *args, **kwargs)
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\.venv\lib\site-packages\django\views\generic\edit.py", line 153, in post
    return self.form_invalid(form)
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\cryptosite_server\app\views.py", line 98, in form_invalid
    return super().form_invalid(form)
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\.venv\lib\site-packages\django\views\generic\edit.py", line 67, in form_invalid
    return self.render_to_response(self.get_context_data(form=form))
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\cryptosite_server\app\views.py", line 87, in get_context_data
    context = super().get_context_data(**kwargs)
  File "C:\Users\User\OneDrive\Рабочий стол\PycharmProjects\cryptosite\.venv\lib\site-packages\django\views\generic\detail.py", line 95, in get_context_data
    if self.object:
AttributeError: 'TestDetails' object has no attribute 'object'

问题原因

直接同时继承DetailView和FormView时,POST请求的处理流程由FormView主导,不会触发DetailView初始化self.object的逻辑。当表单验证失败调用form_invalid,进而调用get_context_data时,DetailView的get_context_data尝试访问self.object,但该属性未被赋值,因此抛出错误。

解决方案

方案1:在dispatch方法中提前初始化object

重写dispatch方法,确保无论GET还是POST请求,都先获取对象并赋值给self.object:

class TestDetails(DetailView, FormView):
    model = Test
    form_class = QuestionForm
    context_object_name = 'test'
    pk_url_kwarg = 'test_id'
    template_name = 'app/views/test_details.html'

    def dispatch(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super().dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        test_id = self.kwargs.get('test_id')
        context = super().get_context_data(**kwargs)
        context['title'] = f'Тест - {test_id}'
        context['questions'] = Question.objects.filter(test_id=test_id)
        return context

    def form_valid(self, form):
        print(form.cleaned_data)
        return super().form_valid(form)

    def form_invalid(self, form):
        print(form.cleaned_data)
        return super().form_invalid(form)

方案2:改用SingleObjectMixin与FormView组合继承

避免多重继承可能的方法冲突,直接使用SingleObjectMixin(DetailView的底层混入类)和FormView组合,并在GET/POST方法中初始化object:

from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import FormView

class TestDetails(SingleObjectMixin, FormView):
    model = Test
    form_class = QuestionForm
    context_object_name = 'test'
    pk_url_kwarg = 'test_id'
    template_name = 'app/views/test_details.html'

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super().get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super().post(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        test_id = self.kwargs.get('test_id')
        context = super().get_context_data(**kwargs)
        context['title'] = f'Тест - {test_id}'
        context['questions'] = Question.objects.filter(test_id=test_id)
        return context

    def form_valid(self, form):
        print(form.cleaned_data)
        return super().form_valid(form)

    def form_invalid(self, form):
        print(form.cleaned_data)
        return super().form_invalid(form)

方案3:在get_context_data中检查并初始化object

如果不想修改dispatch或继承结构,可以在get_context_data开头检查self.object是否存在,不存在则主动获取:

def get_context_data(self, **kwargs):
    if not hasattr(self, 'object'):
        self.object = self.get_object()
    test_id = self.kwargs.get('test_id')
    context = super().get_context_data(**kwargs)
    context['title'] = f'Тест - {test_id}'
    context['questions'] = Question.objects.filter(test_id=test_id)
    return context

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 01:52:33