Django South - Create Not Null ForeignKey

只愿长相守 提交于 2019-12-20 16:53:21

问题


I have a Model

class Mystery(models.Model):
    first = models.CharField(max_length=256)
    second = models.CharField(max_length=256)
    third = models.CharField(max_length=256)
    player = models.ForeignKey(Player)

I added the player ForeignKey but when I try to migrate it using South it seems that I can't create this whith a null=False. I have this message :

The field 'Mystery.player' does not have a default specified, yet is NOT NULL. Since you are adding this field, you MUST specify a default value to use for existing rows. Would you like to:
1. Quit now, and add a default to the field in models.py
2. Specify a one-off value to use for existing columns now

I use this command :

manage.py schemamigration myapp --auto

Thanks a lot !


回答1:


Another option is to create a data migration before adding the ForeignKey, in which you create a new Player instance with a specific id. Be sure that that id does not exist previously in your database.

1.Create the data migration file

$ ./manage.py datamigration myapp add_player
Created 00XX_add_player.py

2.Edit the forwards and backwards methods of the file:

def forwards(self, orm):
    orm['myapp.Player'].objects.create(name=u'Very misterious player', id=34)

def backwards(self, orm):
    # Haven't tested this one yet
    orm['myapp.Player'].objects.filter(id=34).delete()

3.Add the ForeignKey to your Mistery class and migrate the schema again. It will ask for the default value to your data migration id, in this example, 34.

 $ ./manage.py schemamigration --auto myapp
 ? The field 'Mistery.player' does not have a default specified, yet is NOT NULL.
 ? Since you are adding this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  1. Quit now, and add a default to the field in models.py
 ?  2. Specify a one-off value to use for existing columns now
 ? Please select a choice: 2
 ? Please enter Python code for your one-off default value.
 ? The datetime module is available, so you can do e.g. datetime.date.today()
 >>> 34
 + Added field player on myapp.Mistery
Created 0010_auto__add_field_mistery_player.py. You can now apply this migration with: ./manage.py migrate myapp

4.Finally run the migrate command and it will execute the migrations in sequential order, inserting the new Player and updating all the Mistery rows with the reference to your new Player.




回答2:


This is best accomplished in 3 migrations.

Step 1. Create the new model and allow player to be null: player = models.ForeignKey(Player, null=True)

Step 2. Run ./manage.py schemamigration <app> --auto

Step 3. Run ./manage.py datamigration <app> set_default_players

Step 4. Update forwards and backwards in <app>/migrations/<number>_set_default_players.py to use whatever logic you like for setting the default player. Ensure that every Mystery object has a value for player.

Step 5. Update the Mystery model so that player has null=False.

Step 6. Run ./manage.py schemamigration <app> --auto

Step 7. Run ./manage.py migrate <app>




回答3:


If your database already contains Mystery objects, then south must know, what value put into player field, because it cannot be blank.

One possible solution:

choose

    2. Specify a one-off value to use for existing columns now

and then enter 1. So all of your existing Mystery objects will now point to Player with pk = 1. Then you can change (if needed) this in admin page.



来源:https://stackoverflow.com/questions/16210272/django-south-create-not-null-foreignkey

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!