Django — how to move a model to another app
Sometimes application architecture was designed wrongly or requirements changed during the development process. The result is that the project becomes huge, and bug fixing, improvements, and maintenance start terrifying you.
One way to refactor your project is to split it into smaller apps and now you will learn an easy way how you can perform it without losing your data. There are several methods, and the short one is to reference the old model.
Let’s say we want to move everything related to documents to a separate app.
- Let's create a new app in the project root and organize it somehow like this.
urls.py
can look like this if you don’t have any API points (or with API URLs if there are):
app_name = 'documents'__all__ = ['urlpatterns']urlpatterns = []
__init__.py
should be empty.
Move all the desired code to the new files.
2. For each model moved — change the Meta in the new models.py
class Documents(models.Model):
...
class Meta:
...
db_table = 'old_documents'
...
3. Add your new app to settings.py
INSTALLED_APPS = [
...
'documents',
...
]
4. Add your module URL to urls.py
urlpatterns = [
...
path('documents/', include(('documents.urls', 'documents'))),
...
]
5. Delete the initial model from the initial models.py.
6. Change imports and routes over the entire project if needed.
7. Run python manage.py makemigrations
If migrations for the new app were not created automatically - run it manually e.g. python manage.py makemigrations documents
8. This step is the most important one. In EVERY created migration (for the old app and for the new one) make changes in a way that no operation will be actually performed (deleting the old model and creating a new one).
Basically, you need to wrap autogenerated operations
block into
operations = [
migrations.SeparateDatabaseAndState(
state_operations=[
<GENERATED_OPERATIONS>
],
database_operations=[],
),
]
For example, if your autogenerated migrations look like this
operations = [
migrations.DeleteModel(
name='Documents',
),
migrations.RemoveField(
model_name='documents',
name='documents_template',
),
migrations.DeleteModel(
name='DocumentsTemplate',
),
]
you should wrap them accordingly
operations = [
migrations.SeparateDatabaseAndState(
state_operations=[
migrations.DeleteModel(
name='Documents',
),
migrations.RemoveField(
model_name='documents',
name='documents_template',
),
migrations.DeleteModel(
name='DocumentsTemplate',
),
],
database_operations=[],
),
]
9. Run python manage.py migrate --plan
to check that the migration plan meets your expectations.
10. Run migrations python manage.py migrate
to run it automatically
Or run them manually: python manage.py migrate NEWAPP
where NEWAPP is the new module plus python manage.py migrate OLDAPP
11. Run the server and check that the new app appears in the admin panel.