How can I change existing token in the authtoken of django-rest-framework?

django, django-models, django-rest-framework

Solution

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 :)

Problem

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"

Original source