(improvement) makemigrations app_label can and should always create migration only for this app_label

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

(improvement) makemigrations app_label can and should always create migration only for this app_label

nnseva
Hi All,

The %subj% is a discussion for the ticket https://code.djangoproject.com/ticket/30467

The theme has been touched also in the following threads:
https://groups.google.com/forum/#!searchin/django-developers/makemigrations$20dependency%7Csort:date/django-developers/WgFacUFvgfs/cDoYO018NzIJ
<a href="https://groups.google.com/forum/#!searchin/django-developers/makemigrations|sort:date/django-developers/iClIpvwlbAU/53ZBk-y_AgAJ">https://groups.google.com/forum/#!searchin/django-developers/makemigrations|sort:date/django-developers/iClIpvwlbAU/53ZBk-y_AgAJ
<a href="https://groups.google.com/forum/#!searchin/django-developers/makemigrations|sort:date/django-developers/IG5ZSRRp8Rw/a0VSjrJMAQAJ">https://groups.google.com/forum/#!searchin/django-developers/makemigrations|sort:date/django-developers/IG5ZSRRp8Rw/a0VSjrJMAQAJ

What happens?

Now, if the makemigration is running for the only app_label A, it sometimes tries to create a migration for other app_label B implicitly, if the A contains a ForeignKey field referring a model in the B with the unsynchronized state.

What proposed?

Always avoid implicit migration creation for the referred application B.

Why the makemigrations CAN always do it?

If the application A has a ForeinKey reference to the application B without migrations, it means, that all tables in the application B are already created on the stage of initial migration and need not be migrated.

If the ForeignKey in the application A refers to the existent (in the migration state) model of the application B, but with the not synchronized state, the created migration may depend on the last existent migration of the application A instead of newly created one almost anyway.

The only inconsistent unsynchronized change leading to possible errors may be:
- changing the primary key of the referred model in application B
- creating a brand new referred model in application B

Change in the primary key leads to changes in the ForeignKey field attributes, implicit, or explicit. Such a change may be detected separately and agnostic way: determining changes only in the ForeignKey field attribute values.
Non-existent referred model in the state can also be detected easy, and leads to other error detected on the stage of migration itself, or while runtime (non-existent table for the model).

Such an inconsistent unsynchronized change may lead to error message generated by the `makemigrations A`, like `the application A refers to the application B which needs to have synchronized migration state, please create a migration for B first`.

Why the makemigrations SHOULD always do it?

What is application B? It may be:

- own project application
- third-party application

If application B is own project application, the project owner always can explicitly create a new migration for the application B to synchronize its state. Such a way, it is enough to have an error message such described above instead of implicit creation of such a migration creating migration for application A.

The most problem is a third-party application.

The third-party application is such a thing that should not be changed by the programmer. It is installed in the system area or virtual environment as a rule.

If the third-party application B is installed into the system area, the `makemigration A` command will lead to file access error if tries to create a migration for application B automatically.
If the third-party application B is installed into the virtual environment, the `makemigration A` command will lead to migration conflict, and/or refer to non-existent migration in case of shared development of the project.

Why the third-party application may have inconsistent migration state?

1. Of course, the third-party application B can really have inconsistent migration state because of third-party programmers error. If such a problem is significant for the project, it is detected by the error message described above, or others, which allow the programmer of the project to make an explicit decision, what to do next.

The project programmer can create a lost (temporary) migration for application B, it is a resolution compatible with the existent now. He also can avoid using this application at all, create an issue in the tracker, etc... Anyway, the programmer makes a decision explicitly and knows about all the effects of it.

2. The inconsistent migration state may also be caused by dependencies of settings, different in the application when migration for B has been created, and project when the migration for A is created.

Such a dependency may lead to insignificant changes in the model state which don't change ForeignKey attributes. It might be changing in field verbose name, enum field choices, file field storage, or other field attributes not related to the database table metadata state.

Unfortunately, even the solution with the __eq__ substitution described in the documentation does not work to avoid unnecessary migration detection in such a case. A field attribute value of the complex deconstructible type leads to wrong state inconsistency detection when changed, even when have an __eq__ substitution, because of doing deep_deconstruct results comparison instead of direct comparison in the Django code.

With best regards,
Vsevolod Novikov

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/907e3921-eafb-4036-b5cc-95647b9921f0%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.