Django: 删除对象导致IndexError

0 投票
3 回答
578 浏览
提问于 2025-04-18 02:50

我有点困惑,需要一些帮助。

我正在使用 ModelFormset 来显示我的对象,然后通过 Ajax 动态地删除它们,最后又通过 Ajax 调用将所有对象保存起来。整个过程都是动态的,页面没有任何时候会重新加载。

问题是,当 Django 尝试在删除一个或两个对象后,通过 Ajax 保存整个表单集时,它会去查找已删除的对象,这时就会出现一个错误:IndexError: list index out of range,因为这些对象已经不在查询集中。

这是我显示和保存表单集的方式(简化版 - 我觉得错误就是出在这里):

def App(request, slug):
    TopicFormSet = modelformset_factory(Topic, form=TopicForm, extra=0, fields=('name',), can_delete=True)
    SummaryFormSet = modelformset_factory(Summary, form=SummaryForm, extra=0, fields=('content',), can_delete=True)
    tquery = user.topic_set.all().order_by('date')
    squery = user.summary_set.all().order_by('date')
    # saving formsets:
    if request.method == 'POST' and request.is_ajax():
        # the following two lines is where the error comes from:
        t_formset = TopicFormSet(request.POST) # formset instance
        s_formset = SummaryFormSet(request.POST) # formset instance
        s_formset.save()
        t_formset.save()
    return render (blah...)

这是我删除对象的方式(这是一个不同的视图):

def Remove_topic(request, slug, id):
    topic = Topic.objects.get(pk=id)
    summary = Summary.objects.get(topic = topic) # foreign key relatonship

    topic.delete()
    summary.delete()

    # Ajax stuff....
    if request.is_ajax():
        return HttpResponse('blah..')

我尝试在实例化 t_formsets_formset 时放置 queryset = tqueryqueryset = squery,但没有帮助。我该怎么办?我正在使用 Postgres 数据库,如果这有用的话。

错误信息:

> File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/contrib/auth/decorators.py", line 25, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/home/eimantas/Desktop/Projects/Lynx/lynx/views.py", line 122, in App
    t_formset = TopicFormSet(request.POST, queryset = tquery)
  File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py", line 441, in __init__
    super(BaseModelFormSet, self).__init__(**defaults)
  File "/usr/local/lib/python2.7/dist-packages/django/forms/formsets.py", line 56, in __init__
    self._construct_forms()
  File "/usr/local/lib/python2.7/dist-packages/django/forms/formsets.py", line 124, in _construct_forms
    self.forms.append(self._construct_form(i))
  File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py", line 468, in _construct_form
    kwargs['instance'] = self.get_queryset()[i]
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 198, in __getitem__
    return self._result_cache[k]
IndexError: list index out of range

3 个回答

0

这和第二个视图以及Ajax调用没什么关系。我觉得你可能搞混了管理表单的字段。比如说像initial_form_counttotal_form_count这些。

还有一个重要的点。在检查表单是否有效之前,不要保存表单集:

t_formset = TopicFormSet(request.POST)
if t_formset.is_valid():
    t_formset.save()
0

这可能是一个级联删除的情况,已经在删除摘要对象了:

当一个被外键引用的对象被删除时,Django 默认会模拟 SQL 中的 ON DELETE CASCADE 约束,这样也会删除包含这个外键的对象。

https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.on_delete

0

在G+小组里,有人告诉我,从技术上讲,重置或“重新加载”查询集是可能的,但这样做在各个层面上都很难维护,而且可能没有什么好处。有人建议我在保存表单集的时候,逐个检查每个对象是否成功保存(我需要重写form = TopicFormform = SummaryFormsave()方法)。

最后,我决定不使用表单集,而是逐个列出并保存每个对象,这样对我和我应用的业务逻辑来说会更好。

撰写回答