[Django] #22689: inlines with sliced and ordered querysets save incorrectly when underlying data has changed since page load

7 views
Skip to first unread message

Django

unread,
May 23, 2014, 6:28:26 PM5/23/14
to django-...@googlegroups.com
#22689: inlines with sliced and ordered querysets save incorrectly when underlying
data has changed since page load
-------------------------------+--------------------------
Reporter: cspinelive | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 1.7-beta-2
Severity: Normal | Keywords: admin inline
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------
Our Client model's Change page has an tabular inline for the client's
Financial Transactions. We use a custom formset to limit the transactions
to the most recent 5 and to order them from newest to oldest.


{{{
class FinancialTransactionInlineFormset(BaseInlineFormSet):
def get_queryset(self):
qs = super(FinancialTransactionInlineFormset,
self).get_queryset()
return qs.order_by('-id')[:5]
}}}

If while you have the Change Client page open, someone else adds a new
transaction, when you do the same, you'll find that while yours was added,
some of the other transactions have changed. The history page reports
that you were the one that changed them. In actuality, all you did was
use the blank row at the bottom to add a new one.

{{{
Changed transaction_type for financial transaction "cli...@company.net |
123
Changed transaction_type for financial transaction "cli...@company.net |
456
Changed transaction_type for financial transaction "cli...@company.net |
789
}}}

This is what I experienced in django 1.7b4.

It seems like django is having trouble deciding which inline forms have
changed and which ones are new

In django 1.4.5 it throws an error because

{{{
obj = self._existing_object(pk_value)
}}}

in BaseModelFormset is setting obj to None

{{{
def save_existing_objects(self, commit=True):
self.changed_objects = []
self.deleted_objects = []
if not self.initial_forms:
return []

saved_instances = []
for form in self.initial_forms:
pk_name = self._pk_field.name
raw_pk_value = form._raw_value(pk_name)

# clean() for different types of PK fields can sometimes
return
# the model instance, and sometimes the PK. Handle either.
pk_value = form.fields[pk_name].clean(raw_pk_value)
pk_value = getattr(pk_value, 'pk', pk_value)

obj = self._existing_object(pk_value)
if self.can_delete and self._should_delete_form(form):
self.deleted_objects.append(obj)
obj.delete()
continue
if form.has_changed():
self.changed_objects.append((obj, form.changed_data))
saved_instances.append(self.save_existing(form, obj,
commit=commit))
if not commit:
self.saved_forms.append(form)
return saved_instances
}}}


{{{
Traceback (most recent call last):

File "/usr/local/lib/python2.7/dist-
packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)

File "/usr/local/lib/python2.7/dist-
packages/django/contrib/admin/options.py", line 366, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)

File "/usr/local/lib/python2.7/dist-
packages/django/utils/decorators.py", line 91, in _wrapped_view
response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python2.7/dist-
packages/django/views/decorators/cache.py", line 89, in _wrapped_view_func
response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python2.7/dist-
packages/django/contrib/admin/sites.py", line 196, in inner
return view(request, *args, **kwargs)

File "/usr/local/lib/python2.7/dist-
packages/django/utils/decorators.py", line 25, in _wrapper
return bound_func(*args, **kwargs)

File "/usr/local/lib/python2.7/dist-
packages/django/utils/decorators.py", line 91, in _wrapped_view
response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python2.7/dist-
packages/django/utils/decorators.py", line 21, in bound_func
return func(self, *args2, **kwargs2)

File "/usr/local/lib/python2.7/dist-packages/django/db/transaction.py",
line 224, in inner
return func(*args, **kwargs)

File "/usr/local/lib/python2.7/dist-
packages/django/contrib/admin/options.py", line 1056, in change_view
change_message = self.construct_change_message(request, form,
formsets)

File "/usr/local/lib/python2.7/dist-
packages/django/contrib/admin/options.py", line 682, in
construct_change_message
'name': force_unicode(changed_object._meta.verbose_name),

AttributeError: 'NoneType' object has no attribute '_meta'
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/22689>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jun 16, 2014, 8:11:08 PM6/16/14
to django-...@googlegroups.com
#22689: inlines with sliced and ordered querysets save incorrectly when underlying
data has changed since page load
-------------------------------+--------------------------------------
Reporter: cspinelive | Owner: nobody
Type: Bug | Status: closed
Component: contrib.admin | Version: 1.7-beta-2
Severity: Normal | Resolution: duplicate

Keywords: admin inline | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by timo):

* status: new => closed
* needs_better_patch: => 0
* resolution: => duplicate
* needs_tests: => 0
* needs_docs: => 0


Comment:

I think it's a probably a duplicate of #15574.

--
Ticket URL: <https://code.djangoproject.com/ticket/22689#comment:1>

Django

unread,
Feb 25, 2015, 9:17:25 AM2/25/15
to django-...@googlegroups.com
#22689: inlines with sliced and ordered querysets save incorrectly when underlying
data has changed since page load
-------------------------------+--------------------------------------

Reporter: cspinelive | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 1.7
Severity: Normal | Resolution:

Keywords: admin inline | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by Ernest0x):

* status: closed => new
* version: 1.7-beta-2 => 1.7
* resolution: duplicate =>


Comment:

Replying to [comment:1 timo]:


> I think it's a probably a duplicate of #15574.

Why do you think this is a duplicate of #15574?

I am experiencing exactly the same behavior as the OP reports with 1.7.4
(inlines with slicing on the formset's queryset). In addition, in my case,
although the admin logs say that the objects were changed, in fact, they
were (re-)added as new (same values, different ids)! It seems that
something really bad is happening...

--
Ticket URL: <https://code.djangoproject.com/ticket/22689#comment:2>

Django

unread,
Feb 25, 2015, 9:33:35 AM2/25/15
to django-...@googlegroups.com
#22689: inlines with sliced and ordered querysets save incorrectly when underlying
data has changed since page load
-------------------------------+------------------------------------

Reporter: cspinelive | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 1.7
Severity: Normal | Resolution:
Keywords: admin inline | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------+------------------------------------
Changes (by timgraham):

* stage: Unreviewed => Accepted


Comment:

I meant that I think solving #15574 would fix the issue. But sure, we can
leave this ticket open.

--
Ticket URL: <https://code.djangoproject.com/ticket/22689#comment:3>

Reply all
Reply to author
Forward
0 new messages