How can I move a field from one model to another, and still retain the data?

微笑、不失礼 提交于 2020-06-24 22:48:30

问题


To simplify, I have a model, say,

class Parent(models.Model):
    field_a = models.CharField(max_length=40)

and another model that holds an image field, that ties itself to a parent instance via foreign key:

class ParentPicture(models.model):
    parent = models.ForeignKey(Parent)
    picture = models.ImageField(upload_to=upload_path)
    is_used = models.BooleanField(default=False)

The original plan was to support multiple pictures for the parent, and only have one in use at any one time, but now, I'd like to have support for just one picture, and include it in the parent model, so that ParentPicture can be destroyed, and have Parent look like so:

class Parent(models.Model):
    field_a = models.CharField(max_length=40)
    picture = models.ImageField(upload_to=upload_path)

I'm unsure of the best way to move the picture field over to the new model, and include the instances from the ParentPicture that have the is_used flag.

Is there a simple way to do this automatically with Django, or would I need to make the change to the Parent model, migrate the change, then run a script to go through the ParentPicture model and copy appropriately, and then only after that's been done, remove the ParentPicture model?

Thanks for any help/advice!


回答1:


I think there is not an 'automatic' way to move the field, so you could do:

  1. Add picture field to Parent class
  2. Generate and run a schema migration
  3. Write and run a data migration to populate the new picture field with values in the model ParentPicture
  4. Delete old/obsolete models/fields, generate a new schema migration and run it



回答2:


This is a multistep process. First you need to add the fields to as follows and then do ./manage.py makemigrations

class Parent(models.Model):
    field_a = models.CharField(max_length=40)    
    picture = models.ImageField(upload_to=upload_path)
    is_used = models.BooleanField(default=False)

For the second step you have two options. The first is to create a migrations.RunPython that queries the ParentPicture table and updates the Parent table with the values from it. This wouldn't involve in raw sql but it would be inefficient. On the other hand if you have only a few rows it wouldn't matter.

  for p in ParentPicture.objects.all():
      Parent.objects.filter(pk = p.parent_id
           ).update(picture=p.picture, is_used=p.is_used)

The alternative is to use a migrations.RunSQL with an UPDATE JOIN type of query. This will be efficient and recommended if you have a large number of records. In mysql your query might look like this:

UPDATE app_parent p 
   INNER JOIN app_parentpicture pp on
      p.id = pp.parent_id
   SET p.picture = pp.picture, 
      p.is_used = pp.is_used

Step 3, do you really need to drop the old table at this stage? Why not wait until some thorough testing has been done?



来源:https://stackoverflow.com/questions/37171077/how-can-i-move-a-field-from-one-model-to-another-and-still-retain-the-data

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