首页 > 解决方案 > Django:尝试使用自引用默认值进行用户迁移

问题描述

我正在尝试为添加到我的用户模型的字段设置默认值,但我必须做很多杂技才能使其正常工作。

我想添加一个具有在函数中定义的默认值的“标识符”SlugField,如下所示:

def create_identifier():
    while True:
        identifier = ''.join(random.SystemRandom().choice('23456789BCDFGHJKMNPQRSTVWXYZ') for _ in range(15))
        if not User.objects.filter(identifier=identifier).exists():
            return identifier

class User(AbstractUser):
    identifier = models.SlugField(default=create_identifier, max_length=16)

    def __str__(self):
        return self.username

这个确切的场景适用于不同的(非用户)nodel 类,但是当我尝试使用此代码为用户运行迁移时,我得到:

Traceback (most recent call last):
  File "manage.py", line 29, in <module>
    execute_from_command_line(sys.argv)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
    utility.execute()
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/core/management/__init__.py", line 365, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/core/management/base.py", line 332, in execute
    self.check()
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/core/management/base.py", line 364, in check
    include_deployment_checks=include_deployment_checks,
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 58, in _run_checks
    issues.extend(super()._run_checks(**kwargs))
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/core/management/base.py", line 351, in _run_checks
    return checks.run_checks(**kwargs)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/core/checks/registry.py", line 73, in run_checks
    new_errors = check(app_configs=app_configs)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/contrib/auth/checks.py", line 74, in check_user_model
    if isinstance(cls().is_anonymous, MethodType):
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/models/base.py", line 469, in __init__
    val = field.get_default()
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 775, in get_default
    return self._get_default()
  File "/home/myprojectname/myprojectname/myprojectname/users/models.py", line 34, in create_identifier
    if not User.objects.filter(identifier=identifier).exists():
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/models/query.py", line 715, in exists
    return self.query.has_results(using=self.db)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/models/sql/query.py", line 509, in has_results
    return compiler.has_results()
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1037, in has_results
    return bool(self.execute_sql(SINGLE))
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1068, in execute_sql
    cursor.execute(sql, params)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
    return super().execute(sql, params)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/myprojectname/.local/share/virtualenvs/myprojectname-Uef4Bstr/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "users_user" does not exist
LINE 1: SELECT (1) AS "a" FROM "users_user" WHERE "users_user"."iden...

我必须像这样手动修改迁移:

migrations.CreateModel(
    name='User',
    fields=[
        ...

        ('identifier', models.SlugField(default='', max_length=16)),

        ...
),

migrations.AlterField(
    model_name='user',
    name='identifier',
    field=models.SlugField(default=myprojectname.users.models.create_identifier, max_length=16),
),

然后,如果我最初在 models.py 中设置default=''并运行迁移它可以工作,我可以在事后改回default=create_identifier 。

class User(AbstractUser):
    identifier = models.SlugField(default='', max_length=16)

    def __str__(self):
        return self.username

有什么方法可以让我不必通过这些措施就可以完成这项工作?

编辑:如果字段为空或为空,我最好留下空白=真,空=真并覆盖模型的保存()方法来更改值?

标签: djangomigrationmodels

解决方案


我似乎通过将create_identifier修改为以下内容解决了这个问题:

def create_identifier():
    while True:
        identifier = ''.join(random.SystemRandom().choice('23456789BCDFGHJKMNPQRSTVWXYZ') for _ in range(15))
        try:
            present = User.objects.first()
        except:
            present = None

        if present:
            if not User.objects.filter(identifier=identifier).exists():
                return identifier
        else:
            return identifier

推荐阅读