Saving fails:
from rest_framework.authtoken.models import Token
token = Token.objects.get(user=user1)
token.key = '1'
token.save()
gives
IntegrityError: duplicate key value violates unique constraint "authtoken_token_user_id_key"
I had the same issue today so I thought I should leave a response for future reference explaining why this happens.
The key
column is the primary key of the Token
table.
If you edit a model instance, when you call the save()
django has to figure whether it has to do an INSERT
or an UPDATE
. It does so by looking for an existing row (using the primary key) in the database, since you just changed the primary key it won't find it and will assume it has to insert a new row. Since you already have a row for that user and the user_id column has a unique constraint the insert will fail.
An example with the corresponding generated sql.
>>> t = Token.objects.get(user=User.objects.get(id=1))
>>> t.key
u'b0750c801a1b075051ed084841f3001bb55dd1f1'
>>> t.key = t.generate_key()
'cafb2efb9b26912d60fc5a0a75b2b7ba0348a2ec'
t.save()
That save()
call renders
SELECT (1) AS "a"
FROM "authtoken_token"
WHERE "authtoken_token"."key" = 'cafb2efb9b26912d60fc5a0a75b2b7ba0348a2ec'
LIMIT 1;
INSERT
INTO "authtoken_token" ("key", "user_id", "created")
VALUES ('cafb2efb9b26912d60fc5a0a75b2b7ba0348a2ec', 1, '2014-03-18 21:48:30.434677+00:00');
There it's clear that the SELECT
is looking for a row with the edited token (cafb2efb9b26912d60fc5a0a75b2b7ba0348a2ec).
Solution:
I guess in this specific case you can just delete the old Token
instance and create a new one (in a single transaction), and it will auto generate the key for you, something like:
token.delete()
Token.objects.create(user=user1)
Note that this is an issue at the ORM level, you can avoid deleting/inserting and just change the value of that row but not using on the save()
method.
Using the update()
method is a good option as mariodev suggested, you'll need to manually generate the token (se above how I did it) and yes it that will change the primary key, the key column, but that's what you wanted in the first place :)
Seems like this would work:
Token.objects.filter(user=user1).update(key='1')
This sample code work for me and update token in database:
t = Token.objects.filter(user=user1)
new_key = t[0].generate_key()
t.update(key=new_key)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With