问题
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:
- Add
picturefield toParentclass - Generate and run a schema migration
- Write and run a data migration to populate the new
picturefield with values in the modelParentPicture - 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