1

I am testing out a small app where I have extended the user model to add some additional information. Users can register via django-allauth (google OAuth2) fine, and entries are added to their database.

class LabUser(models.Model):
    user = models.OneToOneField(User)
    verified = models.BooleanField(default=False, blank=False)
    phone_number = models.CharField(max_length=30, verbose_name="Phone Number", null=True, blank=True)
    home_phone = models.CharField(max_length=30,verbose_name="Home Phone", null=True, blank=True)

    def __unicode__(self):
        return self.user.username

However, when I try to add another user using the django-admin panel, I get the following database error:

IntegrityError: duplicate key value violates unique constraint "lab_manager_labuser_user_id_key"
DETAIL:  Key (user_id)=(24) already exists.

After examining the tables in psql I see the following:

l=# select id, username from auth_user;
 id |    username
----+----------------
 13 | xxxx
 23 | xxxx
 18 | xxxx
 12 | xxxx
 21 | xxxx
 14 | xxxx
 22 | xxxx
  1 | xxxx
(8 rows)

l=# select id, user_id from lab_manager_labuser;
 id | user_id
----+---------
  9 |      13
  1 |       1
 16 |      18
  8 |      12
 10 |      14
 21 |      21
 22 |      22
 23 |      23
(8 rows)

looking at my sequence tables I can see that the values are higher than in their respective model tables:

l=# SELECT sequence_name, last_value FROM auth_user_id_seq;
  sequence_name   | last_value
------------------+------------
 auth_user_id_seq |         24
(1 row)

l=# SELECT sequence_name, last_value FROM lab_manager_labuser_id_seq;
       sequence_name        | last_value
----------------------------+------------
 lab_manager_labuser_id_seq |         25
(1 row)

I have looked at this similar question, but cannot find a reason why this collision should be happening in my case. Both of the sequences appear to be ahead of the values in my table.

i.e. I have tried the following, and while it increments my key, it still causes supposed integrity errors, while these keys clearly do not exist in the database.

SELECT setval('lab_manager_labuser_id_seq', (SELECT MAX(user_id) from lab_manager_labuser)+1)")

Any help would be appreciated.

Update:

I set up a receiver to create a labuser model as follows, maybe I am doing this incorrectly which is causing database mismatches:

@receiver(post_save, sender=User)
def add_labuser(sender, created, instance, **kwargs):
    if created:
        LabUser.objects.create(user=instance)

I think this must be part of the problem, as I can create the user object successfully with the following code in shell:

a = User()
##(add fields)##
a.save()
LabUser.objects.create(user=a)

The reason the duplicate key error is occurring is because I am adding the users through the admin panel with an inline as such:

class LabUserInline(admin.StackedInline):
    model = LabUser
    can_delete = False

Apparently when the user is created through Admin, a LabUser record is automatically created through the inline, before save is called. Then when the post_save signal is received, django tries to create another LabUser record for the same User object, upon which the key collision occurs.

Would anyone know how to circumvent this redundancy?

4
  • It seems that the reason for this problem is not in the posted code. I guess that lab_manager_labuser is inserted twice, which causes this problem. No entry with user_id=24 makes me think that you're using transactions and on error everything is rolled back. Commented Jun 5, 2014 at 15:19
  • I think you're on to something, but it also seems to have to do with the way i'm saving the connected LabUser object when a new user is created. I realized that I can in fact create the objects from the shell. See my update above @ElmoVanKielmo Commented Jun 5, 2014 at 15:43
  • The code in your update makes sense and should not cause this problem... Commented Jun 5, 2014 at 15:49
  • @ElmoVanKielmo made an update. Any advice is appreciated. Commented Jun 9, 2014 at 15:20

1 Answer 1

1

I figured out the issue. While django-allauth wasn't creating a LabUser object by default when a user registered via the signup form, the django admin panel was, as I had implemented the following inline.

class LabUserInline(admin.StackedInline):
    model = LabUser
    can_delete = False
    verbose_name = 'Lab User'
    verbose_name_plural = 'Lab Users'

Further more, it was creating this object before calling user.save(), so when my post_save signal was sent, and the receiver was called, the LabUser object already existed causing a key collision.

I fixed this by removing the post-save signal, and simply creating the object in the save() method of the SignUp form for django-allauth.

    def save(self, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.save()
        labuser = LabUser.objects.create(user=user)
        ...populate fields...
        labuser.save()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.