Re: [Django] #14071: Row duplicated when modifying PK

3 views
Skip to first unread message

Django

unread,
Dec 5, 2019, 8:54:12 AM12/5/19
to django-...@googlegroups.com
#14071: Row duplicated when modifying PK
-------------------------------+--------------------------------------
Reporter: mnbayazit | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 1.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by jedie):

* status: closed => new
* severity: => Normal
* resolution: wontfix =>
* easy: => 0
* ui_ux: => 0
* type: => Bug


Comment:

I just had to deal with the original Problem: ''Row duplicated when
modifying PK''
By changing the primary key in admin you can also get another problem: If
the model has another unique field, then you get the admin error that the
field value is not unique. (This is because django tries to create a
duplicated entry).


The problem is: {{{django.forms.models.BaseModelForm._post_clean()}}} will
do this:
{{{
self.instance = construct_instance(self, self.instance, opts.fields,
opts.exclude)
}}}
And {{{construct_instance()}}} will just change the primary key and this
object will be saved in the end and results in duplication. This is a
known behaviour as the docs says at:
https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.Field.primary_key

If you change the value of the primary key on an existing object and
then save it, a new object will be created alongside the old one.

One way to change the primary key is:
{{{
FooBarModel.objects.filter(id=old_id).update(id=new_id)
}}}

My current work-a-round it to use a own model form:
{{{
class FooBarAdminForm(forms.ModelForm):
def clean_id(self):
old_id = self.instance.id
new_id = self.cleaned_data['id']
if old_id == new_id:
# ID not changed -> nothing to do
return old_id

if FooBarModel.objects.filter(id=new_id).exists():
raise forms.ValidationError('ID already exists')

# Change the primary key without make a new object:
FooBarModel.objects.filter(id=old_id).update(id=new_id)

# replace new created instance, made in self._post_clean() via
construct_instance():
self.instance = FooBarModel.objects.get(id=new_id)

return new_id
}}}
But that's not a perfect solution:

* It's not universal. (Primary key must be {{{id}}})
* Has potential for race-contitions
* Admin ''continue'' will redirect to {{{request.path}}} that will contain
the old ID (But can be fixed via overwriting {{{response_change()}}})

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

Django

unread,
Dec 5, 2019, 8:55:43 AM12/5/19
to django-...@googlegroups.com
#14071: Row duplicated when modifying PK
-------------------------------+--------------------------------------
Reporter: mnbayazit | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 1.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by jedie):

* cc: jedie (added)


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

Django

unread,
Dec 5, 2019, 9:00:35 AM12/5/19
to django-...@googlegroups.com
#14071: Row duplicated when modifying PK
-------------------------------+--------------------------------------
Reporter: mnbayazit | Owner: nobody
Type: Bug | Status: closed
Component: contrib.admin | Version: 1.2
Severity: Normal | Resolution: wontfix

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by felixxm):

* status: new => closed
* resolution: => wontfix


Comment:

[https://docs.djangoproject.com/en/stable/internals/contributing/triaging-
tickets/#closing-tickets Please follow triaging guidelines with regards to
wontfix tickets.]

--
Ticket URL: <https://code.djangoproject.com/ticket/14071#comment:4>

Reply all
Reply to author
Forward
0 new messages