如何更改Django应用程序的名称?

238

我在Django中通过重命名应用程序的文件夹、导入和所有引用(模板/索引)来更改应用程序的名称。但现在,当我尝试运行python manage.py runserver时,我得到了这个错误:

Error: Could not import settings 'nameofmynewapp.settings' (Is it on sys.path?): No module named settings

我该如何调试和解决这个错误?有什么线索吗?


嗨danihp,是的我有。我也在使用virtualenv,不知道这是否有关系。 - André
1
如果你恰好在使用PyCharm,它的“重命名”功能将会极大地帮助你完成这个任务。 - Anto
1
南方不支持这种操作吗? - andilabs
@andi https://dev59.com/eG455IYBdhLWcg3wD_sB - andilabs
1
使用命令 pip install django-rename-app 安装该库,然后运行 python manage.py rename_app <old_app_name> <new_app_name> 命令来重命名应用程序。具体细节请访问 https://github.com/odwyersoftware/django-rename-app。 - Kwaku Biney
12个回答

413

按照以下步骤在Django中更改应用程序名称:

  1. 重命名位于项目根目录中的文件夹
  2. 更改依赖项中对应用程序的任何引用,例如应用程序的 views.pyurls.pymanage.pysettings.py 文件。
  3. 使用以下命令编辑数据库表 django_content_typeUPDATE django_content_type SET app_label='<NewAppName>' WHERE app_label='<OldAppName>'
  4. 如果您有模型,则还必须重命名模型表。对于 postgres,请使用 ALTER TABLE <oldAppName>_modelName RENAME TO <newAppName>_modelName。对于 mysql,我认为是相同的(由 @null_radix 提到)。
  5. (对于 Django >= 1.7) 更新 django_migrations 表以避免重新运行之前的迁移:UPDATE django_migrations SET app='<NewAppName>' WHERE app='<OldAppName>'注意:在评论中有一些争议,是否需要执行此步骤来适用于 Django 1.8+;如果有人确定,请在此处更新。
  6. 如果您的 models.py 的 Meta 类列出了 app_name,请确保也将其重命名(由 @will 提到)。
  7. 如果您已经在应用程序中为 statictemplates 文件夹设置了命名空间,则还需要将这些文件夹重命名。例如,将 old_app/static/old_app 重命名为 new_app/static/new_app
  8. 要重命名 django 的 models,您需要更改 DB 中的 django_content_type.name 条目。对于 postgreSQL,请使用 UPDATE django_content_type SET name='<newModelName>' where name='<oldModelName>' AND app_label='<OldAppName>'
  9. 更新于2021年7月16日:此外,必须删除应用程序内部的 __pycache__/ 文件夹,否则会出现 EOFError: marshal data too short when trying to run the server。由 @Serhii Kushchenko 提到
  10. 更新要重命名的应用程序中的 apps.py 文件以使用新名称。将 "<old_app_name>Config" 类名更改为 "<new_app_name>Config",并在此类中将 name = '<old_app_name>' 更改为 name = '<new_app_name>'

元点(如果使用virtualenv): 值得注意的是,如果您正在重命名包含虚拟环境的目录,则可能会有几个文件在您的环境中包含绝对路径,并且还需要更新。如果您遇到诸如ImportError: No module named ...等错误,这可能是罪魁祸首。(感谢@danyamachine提供此信息)。

其他参考资料: 您可能还想参考以下链接以获得更完整的图片:

  1. Django和South重命名应用程序
  2. 如何将模型从一个Django应用程序迁移到新的应用程序?
  3. 如何更改Django应用程序的名称?
  4. Django South进行反向迁移
  5. 使用Django/South重命名模型的最简单方法?
  6. Python代码(感谢A.Raouf)自动化上述步骤(未经测试的代码。你已经被警告!)
  7. Python代码(感谢rafaponieman)自动化上述步骤(未经测试的代码。你已经被警告!)

3
如果您有模型,您将需要重命名模型表。对于Postgres,请使用ALTER TABLE <oldAppName>_modelName RENAME TO <newAppName>_modelName - null_radix
16
如果您正在使用新的迁移工具,您需要更改现有迁移文件和django_migrations表中的应用程序名称。最好先压缩迁移文件以减少需编辑的内容。 - James
8
要重命名 Postgres 中的序列,也可使用 ALTER SEQUENCE <oldAppName>_<modelName>_<PK>_seq RENAME TO <newAppName>_<modelName>_<PK>_seq;。尽管这并非必要,但是系统本身并不关心名称。列 DEFAULT 存储了一个 OID ('foo_pkey_seq'::regclass),你可以更改序列名称而不会破坏它 - OID 保持不变。 - Konstantine Kalbazov
4
如果您更新答案,包括詹姆斯所说的有关升级迁移文件(例如依赖模块名称)的信息,那就太好了……我找了很久都没搞清楚。 - u3l
3
这是一个管理命令,可以根据 @SrikarAppalaraju 的解决方案对模型进行重命名:https://gist.github.com/rafaponieman/201054ddf725cda1e60be3fe845850a5它接受old_name、new_name和classes作为参数(所有参数的格式都与数据库表格和字段相同)。 - rafaponieman
显示剩余28条评论

42

Django 1.7引入了应用程序注册表,用于存储配置并提供内省功能。这个机制允许您更改几个应用程序属性。

我想要强调的主要观点是,重命名应用程序并不总是必要的:通过应用程序配置,可以解决冲突的应用程序。但如果您的应用程序需要友好的命名,则也是可行的选择。

举个例子,我想将我的投票应用程序命名为“用户反馈”。步骤如下:

polls目录中创建一个apps.py文件:

from django.apps import AppConfig

class PollsConfig(AppConfig):
    name = 'polls'
    verbose_name = "Feedback from users"
将默认的应用程序配置添加到您的 polls/__init__.py 文件中。
default_app_config = 'polls.apps.PollsConfig'

更多应用程序配置信息请参考:https://docs.djangoproject.com/en/1.7/ref/applications/


22

有趣的问题!我很快就要重新命名许多应用程序,所以我进行了一次干运行。

这种方法允许通过原子步骤进行进展,以最小化重命名的应用程序上工作的其他开发人员的干扰。

请参见本答案底部的链接,获取可工作的示例代码。

  1. 为移动准备现有代码
    • 创建一个应用程序配置(将 namelabel设置为默认值)。
    • 将应用程序配置添加到INSTALLED_APPS中。
    • 在所有模型上,明确将db_table设置为当前值。
    • 修改迁移,以便明确定义db_table
    • 确保不需要任何迁移(检查前一步)。
  2. 更改应用程序标签

    • 在应用程序配置中将label设置为新的应用程序名称。
    • 更新迁移和引用新应用程序标签的外键。
    • 为通用类视图的模板更新(默认路径为<app_label>/<model_name>_<suffix>.html)。
    • 运行原始SQL以修复迁移和content_types应用程序(不幸的是,一些原始SQL是不可避免的)。不能在迁移中运行此操作。

UPDATE django_migrations
   SET app = 'catalogue'
 WHERE app = 'shop';

UPDATE django_content_type
   SET app_label = 'catalogue'
 WHERE app_label = 'shop';
  • 确保不需要进行迁移(检查上一步骤)。

  • 重命名表格
    • 删除 "custom" db_table
    • 运行makemigrations,以便Django将表格重命名为“默认值”。
  • 移动文件
    • 重命名模块目录。
    • 修复导入。
    • 更新应用程序配置的 name
    • 更新INSTALLED_APPS引用应用程序配置的位置。
  • 清理
    • 如果不再需要自定义应用程序配置,请删除它。
    • 如果应用程序配置已删除,请不要忘记从INSTALLED_APPS中删除它。

  • 示例解决方案:我创建了app-rename-example,这是一个示例项目,您可以在其中查看我如何一步一步重命名应用程序。

    该示例使用Python 2.7和Django 1.8,但我相信同样的过程也适用于至少Python 3.6和Django 2.1。


    1
    感谢@meshy。它真的帮助我重命名了一个庞大的应用程序。有一个建议,在运行最后一个迁移之后,您可以删除所有迁移文件并重新创建初始迁移文件,这将有助于您进行任何持续集成测试,否则CI将无法创建测试数据库。 - Rohan
    我写这篇文章的初衷是希望一旦迁移过程完成,迁移可以从头开始运行。如果迁移失败了,可能是我们中的某个人漏掉了什么。我会考虑一下,看看是否需要添加其他步骤。 - meshy
    完成所有步骤后,无需保留旧的迁移文件,因为数据库现在具有不同的表名。因此,您可以添加一个额外的步骤来删除所有迁移文件,并重新运行 makemigrations 命令以生成与数据库表一致的新迁移文件。@meshy。但是,您仍然很好地解决了这个问题。谢谢你。 - Rohan
    不客气!我很高兴它对你有用 :) 谢谢你提供额外的信息。对于我的使用情况,保留迁移将非常重要,所以我会在某个时候回来,尝试解决那个特定的问题。 - meshy
    1
    这个游戏计划对我来说非常完美。只要每一步都在所有活动的检出(CI、其他开发人员、生产等)中部署,然后再处理下一步,它就可以完美地运行 - 不存在现有历史迁移的问题。按顺序执行步骤,并在移动到下一步之前在所有地方传播更改。 - user85461
    显示剩余3条评论

    14

    如果您正在使用PyCharm,并且在重命名后项目停止工作:

    1. 编辑运行/调试配置,更改环境变量DJANGO_SETTINGS_MODULE,因为它包括您的项目名称。
    2. 前往设置 / 语言和框架 / Django 并更新设置文件位置。

    1
    这是一种在查找和替换方面让我失望的情况。感谢您指出这一点。 - ruaanvds

    14
    在许多情况下,我认为@allcaps的答案很有效。但有时需要实际重命名应用程序,例如改善代码可读性或防止混淆。大多数其他答案涉及手动数据库操作调整现有迁移,这些方法我不太喜欢。作为替代方案,我喜欢创建一个新的应用程序来实现所需的名称,将所有内容复制到新应用程序中,并确保它能正常工作,然后删除原始应用程序:
    1. 使用所需的名称启动一个应用程序,并将所有代码从原始应用程序复制到其中。确保在新复制的代码中修复命名空间以匹配新的应用程序名称。

    2. makemigrationsmigrate。注意:如果该应用程序有许多外键,则在尝试运行复制应用程序的初始迁移时,可能会出现冲突的反向访问器问题。您必须重命名旧应用程序上的related_name访问器(或添加新的)以解决冲突。

    3. 创建数据迁移,将原始应用程序表中的相关数据复制到新应用程序表中,然后再次migrate

    目前为止,一切仍然正常,因为原始应用及其数据仍在原地。

    1. 现在,您可以重构所有依赖于原始应用的代码,使其仅使用新应用。查看其他答案以了解要注意的示例。

    2. 确认一切正常后,可以删除原始应用程序。这涉及另一个(模式)迁移。

    这样做的好处是每个步骤都使用正常的Django迁移机制,无需手动操作数据库,而且我们可以在源代码控制中跟踪所有内容。此外,我们保留原始应用及其数据,直到确信一切正常。


    不过,如果你想在删除原先的应用之后在全新的安装上运行迁移,猜测这可能会导致问题,对吧?因为数据迁移将指向一个现在不存在的应用程序。 - Ozgur Akcali
    @OzgurAkcali:我认为重新安装不应该是一个问题,因为数据迁移指定依赖关系,就像任何其他迁移一样,并且它们(应该)使用历史模型。由于没有数据需要迁移,因此数据迁移将不会执行任何操作。但是,在完全重新安装的情况下,我会从头开始,因此要么删除所有迁移并创建新的迁移,要么压缩所有迁移。 - djvg
    嗯,是的,他们应该使用历史模型。我在想这样一行代码是否会引起问题:当旧应用程序被删除时,apps.get_model('old_app','ModelName')。如果这样是安全的,那么我猜在第五步之后运行第三步也是安全的。 - Ozgur Akcali
    1
    @OzgurAkcali:我认为当旧应用程序被删除时,apps.get_model()不会引起问题。相反,这就是它的作用:apps.get_model()返回一个“伪”模型,从迁移历史记录中构建而成。在迁移历史记录的那个点上,该应用程序仍然存在。请参见文档此处此处 - djvg
    @OzgurAkcali:虽然我没有明确提到,但第5步(“删除原始应用程序”)也涉及模式迁移。我已经编辑了答案以澄清。因此,在此之后不能执行第3步。 - djvg
    3
    这种方法似乎比这里提到的其他方法更加简洁。 - Ben Davis

    4

    重新迁移的方法可以使代码更加清晰。但是,如果其他应用程序使用外键指向需要重命名的应用程序的模型,则需要进行检查并确保其迁移文件不包含此迁移。

    1. 备份数据库。转储所有表格,包括a)数据+架构以处理可能的循环依赖关系,以及b)仅数据以供重新加载。
    2. 运行测试。
    3. 将所有代码提交到版本控制系统中。
    4. 删除需要重命名的应用程序的数据库表。
    5. 删除权限:delete from auth_permission where content_type_id in (select id from django_content_type where app_label = '<OldAppName>')
    6. 删除内容类型:delete from django_content_type where app_label = '<OldAppName>'
    7. 重命名应用程序的文件夹。
    8. 更改依赖项中对应用程序的任何引用,例如应用程序的views.pyurls.pymanage.pysettings.py文件。
    9. 删除迁移: delete from django_migrations where app = '<OldAppName>'
    10. 如果您的models.py中的Meta类列出了app_name,请确保也将其重命名(由@will提到)。
    11. 如果您在应用程序中设置了statictemplates文件夹的名称空间,则还需要将其重命名。例如,将old_app/static/old_app重命名为new_app/static/new_app
    12. 如果在apps.py中定义了应用程序配置,请将其重命名,并在settings.INSTALLED_APPS中重命名它们的引用。
    13. 删除迁移文件。
    14. 重新创建迁移并进行迁移。
    15. 从备份中加载表格数据。

    3

    简单的4个步骤,无需痛苦或数据丢失即可在Django项目中重命名现有应用程序。

    第一步

    重命名应用程序文件夹。例如,"old_app"是我们的旧名称,"new_app"是我们的新名称。

    mv ./old_app ./new_app

    第二步

    更新所有引用旧文件夹的导入以引用新文件夹。

    例如:

    # Before 
    from myproject.old_app import models
    
    # After
    from myproject.new_app import models
    

    第三步

    Django迁移中更新旧应用程序名称的引用。

    您可能需要进行的示例更改:

    # Before
    
    dependencies = [
        ('old_app', '0023_auto_20200403_1050'),
    ]
    
    # After
    
    dependencies = [
        ('new_app', '0023_auto_20200403_1050'),
    ]
    
    # Before
    
    field = models.ForeignKey(
        default=None, on_delete=django.db.models.deletion.CASCADE,
        to='old_app.Experiment'
    )
    
    # After
    
    field = models.ForeignKey(
        default=None, on_delete=django.db.models.deletion.CASCADE,
        to='new_app.Experiment'
    )
    

    步骤4

    此时进行提交。

    然后,无论您在部署环境中如何运行应用程序迁移,在运行该过程中的迁移之前,请先运行django_rename_app

    例如下面的示例,在“python manage.py migrate --noinput”之前运行。

    # Before
    
    python manage.py collectstatic --noinput
    python manage.py migrate --noinput
    gunicorn my_project.wsgi:application
    
    # After
    
    python manage.py collectstatic --noinput
    python manage.py rename_app old_app new_app
    python manage.py migrate --noinput
    gunicorn my_project.wsgi:application
    

    这将在以下内部Django数据库表中更新应用程序名称:

    • django_content_type
    • django_migrations

    并将所有表的前缀重命名为以新应用程序名称开头,而不是旧名称。

    就这样。

    注意:最好使用IDE/文本编辑器的查找和替换功能来更改各个文件。


    1

    如果您使用 Pycharm,则通过 重构(默认键为Shift+F6)更改应用程序名称非常容易,适用于所有项目文件。
    但请确保删除项目目录及其子目录中的__pycache__文件夹。此外要注意,它还会更改注释的名称,您可以在重构预览窗口中排除注释名称。
    此外,您还需要在重命名后的应用的 apps.py 文件中将 OldNameConfig(AppConfig) 也进行重命名。

    如果您不想丢失数据库数据,则必须手动使用数据库查询执行上述操作。


    值得注意的是,如果您在使用PyCharm时仍然遇到问题,请删除.idea文件夹,然后在PyCharm中重新打开项目。 - Scott Benson

    1

    我的简单替代方案避免了手动数据库操作(类似于https://dev59.com/G2oy5IYBdhLWcg3wo_vo#64133141),在CI/CD中运行良好,并且是可逆的。

    1. 在“旧”应用程序中创建一个空迁移,重命名表、内容类型和迁移记录。包括反向迁移。 例如:
    from django.db import migrations
    
    sql = """
    ALTER TABLE oldapp_examplemodel RENAME TO newapp_examplemodel;
    UPDATE django_migrations SET app ='newapp' WHERE app ='oldapp';
    UPDATE django_content_type SET app_label ='newapp' WHERE app_label ='oldapp';
    """
    
    reverse_sql = """
    ALTER TABLE newapp_examplemodel RENAME TO oldapp_examplemodel;
    UPDATE django_migrations SET app ='oldapp' WHERE app ='newapp';
    UPDATE django_content_type SET app_label ='oldapp' WHERE app_label ='newapp';
    """
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('oldapp', '0001_initial'),
        ]
    
        operations = [
            migrations.RunSQL(sql, reverse_sql)
        ]
    
    将模型表名设置为new_app。 例如:
    class ExampleModel(models.Model):
    
        # normal column definitions...
    
        class Meta:
            db_table = "newapp_examplemodel"  # add this line to the meta class
    
    
    1. 提交、测试并部署以上更改。
    2. 删除第1步创建的迁移。
    3. 重命名/移动旧应用程序并修复所有引用(有关详细信息,请参见https://dev59.com/G2oy5IYBdhLWcg3wo_vo#8408131),包括迁移中的引用。
    4. 从模型元类中删除db_table覆盖。
    5. 提交、测试并部署。

    注:

    • django_migrations表将保留具有旧应用程序的行,因为该行是在我们运行新迁移之后但在其在新应用程序名称下注册之前添加的。可以将其保留不变。
    • 删除迁移是由于上述原因,但也是为了防止将来反向迁移时出现问题,同时也是因为
    • 撤消此应用程序重命名需要签出/部署第3步的提交,然后撤消我们的迁移,然后签出/部署之前的提交

    0

    现在您可以使用django-rename-app工具。

    1. 安装django-rename-app
    2. 将其添加到INSTALLED_APPS设置中
    3. 将您的应用文件夹重命名为新名称
    4. 执行查找和替换以重命名您存储库中的所有旧名称的出现(例如,在vscode中
    5. 提交更改
    6. 运行以下命令: python manage.py rename_app old_app new_app

    有关详细的说明,请访问:


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,