Reputation: 4134
I have the following object:
from django.db import models
class Page(models.Model):
prev_sibling = models.OneToOneField('self', related_name='next_sibling',
null=True, blank=True)
I have several instances of these objects. Let's say, A, B, C
and D
. I have assigned the sibling relationships such that A
has B
as a prev_sibling
, and C
has D
as prev_sibling
.
Now imagine I want to swap B
and D
around. I simply re-assign the attributes, as follows:
A.prev_sibling = D
A.save()
C.prev_sibling = B
C.save()
However, this fails with an IntegrityError
, as I no longer satisfy the uniqueness constraint that is implied by a OneToOneField
after the first save()
.
I tried wrapping the code in a transaction, hoping that that would make sure the save would occur atomically, and thus prevent the temporary constraint breach, like so:
from django.db import transaction
with transaction.atomic():
A.prev_sibling = D
A.save()
C.prev_sibling = B
C.save()
But that did not work. What is the right way to resolve this?
EDIT: For the record: I also tried sequentially assigning and then saving (as follows), but as one might expect, the behaviour is no different.
with transaction.atomic():
A.prev_sibling = D
C.prev_sibling = B
A.save()
C.save()
Upvotes: 2
Views: 425
Reputation: 13731
You're violating the database constraints. You need to clear the other one before you save it so that the database is always in a 'valid' state. Granted, after you set them to None, it's not technically a desired state, but it's a valid one for the database constraints.
This should work for you, but you obviously risk losing the relationship if something bad were to happen between saving them as None
and setting the properties.
Page.objects.filter(id__in=[A.id, C.id]).update(prev_sibling=None)
A.prev_sibling = D
A.save()
C.prev_sibling = B
C.save()
Upvotes: 1