Opened 11 years ago

Closed 11 years ago

#19408 closed Bug (duplicate)

re-delete on a InlineFormSet object causes untrapped exception

Reported by: chriscog Owned by: nobody
Component: Database layer (models, ORM) Version: 1.4
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

If I create a simple two-model application, say the typical Author and Book relationship, and set up any kind of InlineFormSet where an Author lists multiple books, if I set up a circumstance where a book is deleted twice, say open two screens for the Author, delete a book in one screen and "Save", then delete the same book in the other screen and "Save", an exception is raised.

The same scenario can be re-created with one screen by marking the Book to be deleted, then "Save", then hitting the back button, then "Save" again.

This happens both on the Admin screens, or a custom screen using inlineformset_factory.

Code and exception below:

from django.db import models

class Author ( models.Model ):
	name = models.CharField ( max_length=100 )
	def __unicode__ ( self ):
		return self.name
	
class Book ( models.Model ):
	title = models.CharField ( max_length=100 )
	author = models.ForeignKey ( Author )
	def __unicode__ ( self ):
		return self.title
from django.contrib import admin
from models import *

class BookInline ( admin.TabularInline ):
	model = Book
	
class AuthorAdmin ( admin.ModelAdmin ):
	inlines = [ BookInline ]

admin.site.register ( Author, AuthorAdmin )

admin.site.register ( Book )
Environment:


Request Method: POST
Request URL: http://localhost:8000/admin/books/author/1/

Django Version: 1.4.1
Python Version: 2.7.2
Installed Applications:
('django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'books')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/contrib/admin/options.py" in wrapper
  366.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/views/decorators/cache.py" in _wrapped_view_func
  89.         response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/contrib/admin/sites.py" in inner
  196.             return view(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/utils/decorators.py" in _wrapper
  25.             return bound_func(*args, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/utils/decorators.py" in bound_func
  21.                 return func(self, *args2, **kwargs2)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/db/transaction.py" in inner
  209.                 return func(*args, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/contrib/admin/options.py" in change_view
  1049.                                   queryset=inline.queryset(request))
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/forms/models.py" in __init__
  697.                                                 queryset=qs, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/forms/models.py" in __init__
  424.         super(BaseModelFormSet, self).__init__(**defaults)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/forms/formsets.py" in __init__
  50.         self._construct_forms()
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/forms/formsets.py" in _construct_forms
  115.             self.forms.append(self._construct_form(i))
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/forms/models.py" in _construct_form
  706.         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/forms/models.py" in _construct_form
  451.             kwargs['instance'] = self.get_queryset()[i]
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/db/models/query.py" in __getitem__
  190.             return self._result_cache[k]

Exception Type: IndexError at /admin/books/author/1/
Exception Value: list index out of range

Local vars for the last frame:

k	1
self	[<Book: My First Work>]

(I'm going to try and dig into this myself, but wanted to get the bug reported quickly for consideration for 1.5)

Change History (3)

comment:1 by chriscog, 11 years ago

Aaaaand... before anyone says anything :) I upgraded to 1.4.2 and re-tested. Same result.

Environment:


Request Method: POST
Request URL: http://localhost:8000/admin/books/author/1/

Django Version: 1.4.2
Python Version: 2.7.2
Installed Applications:
('django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'books')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/django/contrib/admin/options.py" in wrapper
  366.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Library/Python/2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  89.         response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/contrib/admin/sites.py" in inner
  196.             return view(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/utils/decorators.py" in _wrapper
  25.             return bound_func(*args, **kwargs)
File "/Library/Python/2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/utils/decorators.py" in bound_func
  21.                 return func(self, *args2, **kwargs2)
File "/Library/Python/2.7/site-packages/django/db/transaction.py" in inner
  209.                 return func(*args, **kwargs)
File "/Library/Python/2.7/site-packages/django/contrib/admin/options.py" in change_view
  1049.                                   queryset=inline.queryset(request))
File "/Library/Python/2.7/site-packages/django/forms/models.py" in __init__
  697.                                                 queryset=qs, **kwargs)
File "/Library/Python/2.7/site-packages/django/forms/models.py" in __init__
  424.         super(BaseModelFormSet, self).__init__(**defaults)
File "/Library/Python/2.7/site-packages/django/forms/formsets.py" in __init__
  50.         self._construct_forms()
File "/Library/Python/2.7/site-packages/django/forms/formsets.py" in _construct_forms
  115.             self.forms.append(self._construct_form(i))
File "/Library/Python/2.7/site-packages/django/forms/models.py" in _construct_form
  706.         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
File "/Library/Python/2.7/site-packages/django/forms/models.py" in _construct_form
  451.             kwargs['instance'] = self.get_queryset()[i]
File "/Library/Python/2.7/site-packages/django/db/models/query.py" in __getitem__
  190.             return self._result_cache[k]

Exception Type: IndexError at /admin/books/author/1/
Exception Value: list index out of range

comment:2 by chriscog, 11 years ago

What might not be clear from the above is that the author had two books, and in both screens I was attempting to delete the 2nd book, that's why 'k' was 1, and 'self' only had a single book in it.

Another scenario using the same trick, but deleting different books, gives different results. Say I have three books, and in both screens I attempt to delete the 2nd one. Since 'k' at this time is 1, but the list likely has two elements in it, we won't get that error. However, another error pops up. An untrapped ValidationError:

Environment:


Request Method: POST
Request URL: http://localhost:8000/admin/books/author/1/

Django Version: 1.4.2
Python Version: 2.7.2
Installed Applications:
('django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'books')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/django/contrib/admin/options.py" in wrapper
  366.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Library/Python/2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  89.         response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/contrib/admin/sites.py" in inner
  196.             return view(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/utils/decorators.py" in _wrapper
  25.             return bound_func(*args, **kwargs)
File "/Library/Python/2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/utils/decorators.py" in bound_func
  21.                 return func(self, *args2, **kwargs2)
File "/Library/Python/2.7/site-packages/django/db/transaction.py" in inner
  209.                 return func(*args, **kwargs)
File "/Library/Python/2.7/site-packages/django/contrib/admin/options.py" in change_view
  1055.                 self.save_related(request, form, formsets, True)
File "/Library/Python/2.7/site-packages/django/contrib/admin/options.py" in save_related
  733.             self.save_formset(request, form, formset, change=change)
File "/Library/Python/2.7/site-packages/django/contrib/admin/options.py" in save_formset
  721.         formset.save()
File "/Library/Python/2.7/site-packages/django/forms/models.py" in save
  497.         return self.save_existing_objects(commit) + self.save_new_objects(commit)
File "/Library/Python/2.7/site-packages/django/forms/models.py" in save_existing_objects
  604.             pk_value = form.fields[pk_name].clean(raw_pk_value)
File "/Library/Python/2.7/site-packages/django/forms/fields.py" in clean
  153.         value = self.to_python(value)
File "/Library/Python/2.7/site-packages/django/forms/models.py" in to_python
  988.             raise ValidationError(self.error_messages['invalid_choice'])

Exception Type: ValidationError at /admin/books/author/1/
Exception Value: [u'Select a valid choice. That choice is not one of the available choices.']

comment:3 by Claude Paroz, 11 years ago

Resolution: duplicate
Status: newclosed

Thanks for the report, but this was already reported (#15574).

Note: See TracTickets for help on using tickets.
Back to Top