Opened 8 years ago
Last modified 9 hours ago
#24686 assigned New feature
Support for Moving a model between two Django apps
Reported by: | Alex Rothberg | Owned by: | Durval Carvalho |
---|---|---|---|
Component: | Migrations | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | jedie | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | yes |
Needs tests: | yes | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
An issue that I run into is that at some point one of my apps becomes so large that I decide to split the application into a number of separate logical units. Right now the Django migration system leaves me on my own to write a correct migration to support updating the db to reflect the new multi-app layout.
There is an SO post that attempts to outline a solution but I would suggest trying to detect these model moves and then auto-generating these migrations.
Change History (21)
comment:1 Changed 8 years ago by
Component: | Uncategorized → Migrations |
---|---|
Needs documentation: | set |
Triage Stage: | Unreviewed → Accepted |
Version: | 1.8 → master |
comment:2 Changed 8 years ago by
I'm not sure how the plumbing works for migrations, but I would think the auto-detect logic would work like renaming of fields where if a model with the same name is deleted in one app and created in another the user is prompted with "did you move this model...".
comment:3 Changed 8 years ago by
An actual implementation would supersede #24016.
I don't think the operation to move a model to another app has to be significantly more complex that the current RenameModel
. The autodetection, on first sight, is just a matter of removing this check: https://github.com/django/django/blob/master/django/db/migrations/autodetector.py#L421
I do have some concerns about dependencies. If the migration lives in the old app, the autodetector won't be able to detect that the next migration in the new app depends on the RenameModel
migration in the old app. Likewise, if the migration lives in the new app, the next migration in the old app won't have a dependency on the migration that moves the model. The last case might not be a problem, but I can't say that off the top of my head.
comment:4 follow-up: 5 Changed 8 years ago by
Crazy question, but what about project level migrations?
comment:5 Changed 8 years ago by
Referring back to the example solution from SO:
As soon as you remove the old_app
from installed apps and apply the migrations on an empty database the SeparateDatabaseAndState
operation in new_app
will only create the model in memory but no database table. Therefore it's not an option to migrate data between apps to get rid of one app it this simple form.
Replying to cancan101:
Crazy question, but what about project level migrations?
What about them? You can define settings.MIGRATION_MODULES
and put all app migrations in your project. But I advice you to not do that unless there is a 3rd party app that doesn't have Django migration support. Then this is the way to go to add migrations for that particular app.
Replying to knbk:
I do have some concerns about dependencies. If the migration lives in the old app, the autodetector won't be able to detect that the next migration in the new app depends on the
RenameModel
migration in the old app. Likewise, if the migration lives in the new app, the next migration in the old app won't have a dependency on the migration that moves the model. The last case might not be a problem, but I can't say that off the top of my head.
Sounds about right to me. You will eventually run into a hellhole of dependencies.
comment:6 Changed 8 years ago by
@MarkusH Are you saying that the solution posted on SO won't work?
I was suggesting the project level migrations to address the issues raised by @knbk so that the migrator could see both apps.
comment:7 Changed 8 years ago by
@cancan101, I'm saying that you will have trouble to get the suggested migrations work on an empty database once old_app
is removed from the list of installed apps. To be specific, since you already need to fix the migration dependencies it's probably not that big of a deal to also drop the SeparateDatabaseAndState
and replace it with a CreateModel
operation.
comment:8 Changed 6 years ago by
I also ran into this today, when pulling some models into a separate app.
The stackoverflow post does not work anymore as soon as there are cross-app foreign keys, but this example here does.
In the solution outlined there, a migration inside the new app depends on a migration of the old app (see here), so loading all migrations should at least break as soon if you remove the old app from INSTALLED_APPS ;-)
Given the currently needed amount of manual work, we should really try to detect these movements and produce migrations like above.
comment:9 Changed 6 years ago by
Maybe this could be separated into two separate tasks.
We could first create database operation like django.db.models.MoveToApp
. This alone could save a lot of manual work and confusion for developers.
Second stage would be creating the autodetection mechanism, which would make migrations with this operation automatically.
comment:10 Changed 5 years ago by
In the meantime, I've built a management command to do just that. You can find it at alexei/django-move-model
If someone cared to take a look and submit some feedback, I'd really appreciate it.
comment:11 Changed 3 years ago by
Cc: | jedie added |
---|
comment:12 Changed 3 years ago by
Hi, I have add a method to MigrationAutodetector
to let it find moved models, originally as a fork of .generate_renamed_models()
. It will create at least 2 migrations with SeparateDatabaseAndState
to do the job.
i have create a PR for it. I try not to alter anywhere else in MigrationAutodetector
, maybe others could do it better without this constrain.
I have only one problem, I need to mention the migration of rem_app_label ( commented in PR ) just before new created one ( which I create ).
without it forward plan may works, but backward plan may be incorrect leading to broken backward migration or even data loss.
Adding it manually is not an acceptable answer for Django project.
I dig in code but couldn't find it. anyone can help me?
comment:13 Changed 3 years ago by
Hi again.
Unlike my previous comment and approach, I found that RenameModel
operation is well written even for moving models, so I update it and MigrationAutodetector
to handle moving models.
The move mechanism is completely without SeparateDatabaseAndState
and it will produce at least 2 migrations one for old_app and one for new_app like below.
00zz_new_created_migration_at_old_app.py
class Migration(migrations.Migration): dependencies = [ ('new_app', '00xx_some_migration'), ('old_app', '00yy_pre_migration'), # ... ] operations = [ operations.RenameModel( old_name='MyModel', new_name='MyModel', new_app_label='new_app', ), ]
00vv_new_created_migration_at_new_app.py
class Migration(migrations.Migration): initial = True dependencies = [ ('new_app', '00xx_some_migration'), ('old_app', '00zz_new_created_migration_at_old_app'), ] operations = [ operations.MoveModelPlaceholder( old_name='MyModel', new_name='MyModel', new_app_label='new_app', comment='this is a required noop operation to construct dependencies for moving model', ), ]
note that MoveModelPlaceholder
is a noop operation to construct the dependencies and let forward and backward migrations without problem.
the code is in PR
comment:15 Changed 3 years ago by
Owner: | changed from nobody to Abhishek Bera |
---|---|
Status: | new → assigned |
comment:16 Changed 3 years ago by
Hi, I am new to django development so I started with this documentation ticket. I am struggling with the level of detail I should mention in the document. So far I just updated the param and mentioned what it does. Here is the diff :
ddiff --git a/docs/ref/migration-operations.txt b/docs/ref/migration-operations.txt index d1620cce8e..f4a444e8e9 100644 --- a/docs/ref/migration-operations.txt +++ b/docs/ref/migration-operations.txt ``RenameField`` --------------- -.. class:: RenameField(model_name, old_name, new_name) +.. class:: RenameField(model_name, old_name, new_name, new_app_label=None) Changes a field's name (and, unless :attr:`~django.db.models.Field.db_column` -is set, its column name). +is set, its column name) or moves the Model to `new_app_label`.
Also, what should be the branch name for this PR?
comment:17 Changed 3 years ago by
Update: This is the commit if someone needs it https://github.com/berabhishek/django/pull/1/commits/2a92314a3effca22a43219fcbdfdc6add9ccaf66
comment:18 Changed 3 years ago by
Owner: | Abhishek Bera deleted |
---|---|
Status: | assigned → new |
comment:19 Changed 2 years ago by
Needs tests: | set |
---|
comment:20 Changed 5 days ago by
Owner: | set to Durval Carvalho |
---|---|
Status: | new → assigned |
comment:21 Changed 9 hours ago by
Hi there! I've started working on this ticket and I've opened a PR with my progress so far at https://github.com/django/django/pull/16523. I'm having a little difficulty understanding the autodetector.py code but I believe it's just a matter of spending more time with it. I discovered this ticket through the gsoc2023 blog post for Django and I'm planning to create a proposed solution once I figure out how to implement it. I'm excited to be able to collaborate with my favorite framework!
Not sure about feasibility of detecting/auto-generating, but if not, we could certainly document the SeparateDatabaseAndState solution in docs/howto/writing-migrations.txt.