django-nested-admin
django-nested-admin copied to clipboard
KeyError: 'changed_data' in nested_admin.formsets.save_existing_objects
nested_admin.formsets.save_existing_objects seems to be accessing a field that sometimes does not exist. I'm not quite sure how to generate a MRE here, but this is the traceback from my app logs.
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/django/forms/models.py", line 1538, in to_python
value = self.queryset.get(**{key: value})
File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 637, in get
raise self.model.DoesNotExist(
MyModel.DoesNotExist: MyModel matching query does not exist.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/nested_admin/formsets.py", line 304, in save_existing_objects
pk_value = form.fields[pk_name].clean(raw_pk_value)
File "/usr/local/lib/python3.11/site-packages/django/forms/fields.py", line 198, in clean
value = self.to_python(value)
File "/usr/local/lib/python3.11/site-packages/django/forms/models.py", line 1540, in to_python
raise ValidationError(
django.core.exceptions.ValidationError: ['Select a valid choice. That choice is not one of the available choices.']
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/django/utils/decorators.py", line 46, in _wrapper
return bound_method(*args, **kwargs)
File "/usr/local/lib/python3.11/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python3.11/site-packages/django/contrib/admin/options.py", line 1747, in changeform_view
return self._changeform_view(request, object_id, form_url, extra_context)
File "/usr/local/lib/python3.11/site-packages/django/contrib/admin/options.py", line 1799, in _changeform_view
self.save_related(request, form, formsets, not add)
File "/usr/local/lib/python3.11/site-packages/django/contrib/admin/options.py", line 1255, in save_related
self.save_formset(request, form, formset, change=change)
File "/usr/local/lib/python3.11/site-packages/django/contrib/admin/options.py", line 1243, in save_formset
formset.save()
File "/usr/local/lib/python3.11/site-packages/nested_admin/formsets.py", line 154, in save
instance = self.get_saved_instance_for_form(form, commit, form_instances)
File "/usr/local/lib/python3.11/site-packages/nested_admin/formsets.py", line 237, in get_saved_instance_for_form
instances = self.save_existing_objects([form], commit)
File "/usr/local/lib/python3.11/site-packages/nested_admin/formsets.py", line 314, in save_existing_objects
form.__dict__["changed_data"].append(pk_name)
KeyError: 'changed_data'
@scottgigante did you ever figure this out?
Unfortunately I did not -- I haven't been able to reproduce it.
For me it happened when i used readonly inlines and changed the non-inline object:
class ReadOnlyNestedTabularInline(NestedTabularInline):
extra = 0
def has_add_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
def has_change_permission(self, request, obj=None):
return False
And a custom pk field in the inline model:
class Destination(TimeStampedModel):
uuid = models.UUIDField(primary_key=True)
I managed to address my error. Looking up at the exception stack, the initial exception thrown was a Model not found error. I have some complex model inheritance, polymorphism, and soft deletion going on, so without diving into all that:
My issue was caused by one of the inline models of my ModelAdmin not being accessible/found by the methods that save because it was actually soft-deleted. It was present in the queryset that displayed records on the admin page (bug), but not in the queryset that was used to save objects (expected).
Hence the front end was sending the soft-deleted object id in its payload that could not be found for updating, resulting in exceptions that propagated down to this error.
Thanks @jordanvs for the follow-up! I also use soft deletion to filter querysets, so likely this is the same cause.