2

我正在使用 Django REST 框架设置一个新的 API,我需要向所有现有用户添加 Auth 令牌。文档说要做:

from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token

for user in User.objects.all():
    Token.objects.get_or_create(user=user)

但理想情况下,这应该使用 Django 的新迁移框架来实现。

是否有捷径可寻?

4

2 回答 2

3

这里的诀窍是知道Token使用自定义save()方法来生成唯一token.key但自定义save()方法不在迁移中运行。因此,第一个令牌将有一个空白键,而第二个令牌将失败,IntegrityError因为它们的键也是空白且不唯一。

相反,将generate_key()代码复制到您的迁移中,如下所示:

# Generated with `manage.py makemigrations --empty YOUR-APP`.

import binascii
import os

from django.db import migrations

# Copied from rest_framework/authtoken/models.py.
def generate_key():
    return binascii.hexlify(os.urandom(20)).decode()

def create_tokens(apps, schema_editor):
    User = apps.get_model('auth', 'User')
    Token = apps.get_model('authtoken', 'Token')
    for user in User.objects.filter(auth_token__isnull=True):
        token, _ = Token.objects.get_or_create(user=user, key=generate_key())

class Migration(migrations.Migration):

    dependencies = [
        ('YOUR-APP', 'YOUR-PREVIOUS-MIGRATION'),
    ]

    operations = [
        migrations.RunPython(create_tokens),
    ]

您应该避免将rest_framework代码直接导入迁移中,否则有一天您的迁移将无法运行,因为您决定删除 rest_framework 或更改库的接口。迁移需要及时冻结。

于 2020-05-28T08:02:31.957 回答
2

首先为您希望使用它的应用程序创建一个空迁移。就我而言,我有一个名为userswhere 这种东西的应用程序,所以我运行了:

manage.py makemigrations users --empty

这在我的迁移目录中创建了一个新文件,我可以使用以下内容进行更新:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User

def add_tokens(apps, schema_editor):
    print "Adding auth tokens for the API..."
    for user in User.objects.all():
        Token.objects.get_or_create(user=user)

def remove_tokens(apps, schema_editor):
    print "Deleting all auth tokens for the API..."
    Token.objects.all().delete()

class Migration(migrations.Migration):

    dependencies = [
        ('users', '0002_load_initial_data'),
    ]

    operations = [
        migrations.RunPython(add_tokens, reverse_code=remove_tokens),
    ]
于 2015-09-22T17:52:05.903 回答