首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在现有的Django应用程序中更改主键的最佳方法是什么?

在现有的Django应用程序中更改主键的最佳方法是什么?
EN

Stack Overflow用户
提问于 2010-01-13 18:00:17
回答 10查看 58.7K关注 0票数 51

我有一个应用程序,这是在测试模式。这个应用程序的模型有一些带有显式primary_key的类。因此,Django使用字段,并且不会自动创建id。

代码语言:javascript
复制
class Something(models.Model):
    name = models.CharField(max_length=64, primary_key=True)

我认为这是一个糟糕的想法(参见unicode error when saving an object in django admin),我想搬回去,为我的模型的每个类都有一个id。

代码语言:javascript
复制
class Something(models.Model):
    name = models.CharField(max_length=64, db_index=True)

我已经对模型进行了更改(将每个primary_key=True替换为db_index=True),并希望使用south迁移数据库。

不幸的是,迁移失败,并显示以下消息:ValueError: You cannot add a null=False column without a default value.

我正在评估这个问题的不同解决方法。有什么建议吗?

谢谢你的帮忙

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2010-01-13 19:11:43

同意,你的模型可能是错的。

正式主键应该始终是代理键。再也不会有别的事了。很有说服力。重要的经验教训是:一切都是可变的,即使用户以他们母亲的坟墓发誓,值是不能改变的,这真的是一个可以作为主要的自然关键字。它不是主要的。只有代理可以是主要的。

你在做心内直视手术。不要搞乱模式迁移。您正在替换架构。

  1. 将您的数据卸载到JSON文件中。为此,请使用django自己的内部django-admin.py工具。您应该为每个要更改的表和每个依赖于正在创建的键的表创建一个卸载文件。单独的文件使这一点变得稍微容易一些。
  2. 删除您要从旧模式中更改的表。

依赖于这些表的表将更改其FK;您可以就地更新这些行,或者也可以删除并重新插入这些行--这可能会更简单。

  • 创建新的模式。这只会创建表,这些表是用来读取和重新加载带有新键的数据的changing.

  • Write脚本。这些都很简短,而且非常相似。每个脚本都将使用json.load()从源文件中读取对象;然后,您将从为您构建的JSON tuple-line对象创建您的模式对象。然后您可以将它们插入到数据库中。

你有两个案子。

代码语言:javascript
复制
- Tables with PK's change changed will be inserted and will get new PK's.  These must be "cascaded" to other tables to assure that the other table's FK's get changed also.
- Tables with FK's that change will have to locate the row in the foreign table and update their FK reference.

另类选择。

SQL将所有旧模式重命名为整个新的schema.

  • Write tables.

  • Create,以将所有数据从旧模式迁移到新模式。这将不得不在执行过程中巧妙地重新分配键。

  • 删除重命名的旧表。
票数 91
EN

Stack Overflow用户

发布于 2012-04-21 01:42:38

要将主键更改为south,您可以在数据迁移中使用south.db.create_primary_key命令。要将您的自定义CharField pk更改为标准AutoField,您应该执行以下操作:

1)在模型中创建新字段

代码语言:javascript
复制
class MyModel(Model):
    id = models.AutoField(null=True)

1.1)如果你在这个模型的其他模型中有一个外键,也在这些模型上创建新的伪fk字段(使用IntegerField,然后它将被转换)

代码语言:javascript
复制
class MyRelatedModel(Model):
    fake_fk = models.IntegerField(null=True)

2)创建自动南迁和迁移:

代码语言:javascript
复制
./manage.py schemamigration --auto
./manage.py migrate

3)创建新的数据迁移

代码语言:javascript
复制
./manage.py datamigration <your_appname> fill_id

在数据迁移中,用数字填充这些新的id和fk字段(只需枚举它们)

代码语言:javascript
复制
    for n, obj in enumerate(orm.MyModel.objects.all()):
        obj.id = n
        # update objects with foreign keys
        obj.myrelatedmodel_set.all().update(fake_fk = n)
        obj.save()

    db.delete_primary_key('my_app_mymodel')
    db.create_primary_key('my_app_mymodel', ['id'])

4)在您的模型中,在新的pk字段上设置primary_key=True

代码语言:javascript
复制
id = models.AutoField(primary_key=True)

5)删除旧的主键字段(如果不需要),创建自动迁移并迁移。

5.1)如果您有外键-也删除旧的外键字段(迁移)

6)最后一步-恢复fireign键关系。再次创建真实fk字段,并删除您的fake_fk字段,创建自动迁移但不迁移(!)-您需要修改已创建的自动迁移:而不是创建新的fk并删除fake_fk - rename列fake_fk

代码语言:javascript
复制
# in your models
class MyRelatedModel(Model):
    # delete fake_fk
    # fake_fk = models.InegerField(null=True)
    # create real fk
    mymodel = models.FoeignKey('MyModel', null=True)

# in migration
    def forwards(self, orm):
        # left this without change - create fk field
        db.add_column('my_app_myrelatedmodel', 'mymodel',
                  self.gf('django.db.models.fields.related.ForeignKey')(default=1, related_name='lots', to=orm['my_app.MyModel']),keep_default=False)

        # remove fk column and rename fake_fk
        db.delete_column('my_app_myrelatedmodel', 'mymodel_id')
        db.rename_column('my_app_myrelatedmodel', 'fake_fk', 'mymodel_id')

因此,以前填充的fake_fk变成了一个包含实际关系数据的列,并且在完成上述所有步骤后,它不会丢失。

票数 11
EN

Stack Overflow用户

发布于 2017-10-02 06:00:31

我使用django 1.10.4迁移和MySQL5.5成功做到了这一点,但这并不容易。

我有一个带有几个外键的varchar主键。我添加了一个id字段、迁移数据和外键。这是如何实现的:

  1. 正在添加未来的主键字段。我在我的主模型中添加了一个id = models.IntegerField(default=0)字段,并生成了一个自动migration.
  2. Simple数据迁移来生成新的主键:

def fill_ids(app,schema_editor):模型= apps.get_model('','')表示id,枚举中的代码(Model.objects.all()):code.id = id +1 code.save()类迁移(migrations.Migration):dependencies =…操作= migrations.RunPython(fill_ids)

  • Migrating现有的外键。我写了一个组合迁移:

def change_model_fks(app,schema_editor):apps.get_model= FkModel (‘’,'') #我们想要将模型的主键改为apps.get_model= apps.get_model('','') #通过外键映射引用第一个的其他模型= {}对于Model.objects.all()中的模型: mappingmodel.old_pk_field = model.id #对于FkModel.objects.all()中的fk_model,将旧的主键映射为新的:如果fk_model.model_id: fk_model.model_id = mappingfk_model.model_id #更改引用fk_model.save()类迁移(migrations.Migration):依赖关系=…操作=#删除外键约束migrations.AlterField( model_name='',name='model',field=models.ForeignKey('',blank=True,null=True,db_constraint=False) ),#更改引用名称(Change_model_fks),#将字段从varchar更改为整数,删除索引migrations.AlterField( model_name='',name='model',field=models.IntegerField('',blank=True,null=True) ),

  • 交换主键和还原外键。再说一次,自定义迁移。当我a)从旧的主键中删除了primary_key=True,b)删除了id字段时,我自动生成了这次迁移的基础

类迁移(migrations.Migration):依赖关系=…操作=[# Drop old primary key migrations.AlterField( model_name='',name=‘’,field=models.CharField(max_length=100),),# Create new PRIMARY KEY migrations.RunSQL( 'ALTER TABLE CHANGE id INT (11) NOT NULL primary key AUTO_INCREMENT','ALTER TABLE CHANGE id INT (11) NULL','ALTER TABLE DROP PRIMARY KEY',state_operations=migrations.AlterField( model_name='',name=' id ',field=models.AutoField(auto_created=True,primary_key=True,serialize=False,verbose_name='ID'),) ),#重新创建外键约束migrations.AlterField( model_name='',name='model',field=models.ForeignKey(blank=True,null=True,to=‘.),]

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2055784

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档