问题
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
picture
field toParent
class - Generate and run a schema migration
- Write and run a data migration to populate the new
picture
field 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