#27200: router.allow_migrate without a model/hint, what is it supposed to do? 
Does
it make sense to make that call?
-------------------------------------+-------------------------------------
     Reporter:  Joseph Kahn          |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Migrations           |                  Version:  1.10
     Severity:  Normal               |               Resolution:
     Keywords:  makemigrations,      |             Triage Stage:
  router, allow_migrate              |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Shai Berger):

 Hi Joseph, sorry for taking so long to respond. I'll answer your questions
 in reverse order, starting with the second:

 Replying to [comment:8 Joseph Kahn]:
 >
 > However, there is nothing in the context of a migration to prevent or
 guide me away from saying:
 > Model A1 is in app A and model B is in app B. When I update A1, I need
 to update the corresponding things in B1. When everything is on one
 database this makes sense to do as a data migration, is the idea that if I
 need to update both together they cannot be on one data migration IF they
 are on different shards?

 This has always been the case, and it's not because of a Django design
 decision, but because if some changes need to be done together, then they
 need to be done in a (database) transaction, and that is a little hard to
 do when they are on separate databases.

 > If they should be done on a data migration than in the context of
 looping over one database in the migration, I'm accessing some n other
 databases for all the values of B that need to update. I would assume that
 you are not supposed to write code like that, where a migration on one
 database has some effect on another one?
 >
 > I'm just struggling a little to understand the intention here in multi-
 db scenarios where an update on one db requires another update on another
 database. If the Django team has a clear intent then it just needs a more
 definite explanation in the docs (in my opinion).
 >

 Again -- you describe a case where database integrity is broken by design.
 I believe the developers who made the design decisions here did not give
 such cases a high priority and probably didn't completely think them
 through, and I think Django should not encourage such usage, so I would be
 against making recommendations about it in the docs.

 > edit: I'm in the middle of some stuff right now so sorry if this feels a
 bit scattered. Since I'm allowed to access models in other apps inside a
 data migration, what if those models don't have complete database overlap.
 Or is the intention that if that's the case I'm supposed to only read the
 other model but not write to it, since allow_migrate is this context is in
 an `app_label` context and should only loop over some of those databases?
 I'm not sure if this was super clear so let me know if I need to rephrase
 that.

 I'm not completely sure I got your meaning, but if I did: When migrations
 are run against a given database, we don't expect changes to be made to
 other databases. These other databases can still be read, as the
 migrations can always use data sources other than the migrated database
 (trivially project source files, but also data files, Web API calls,
 whatever).

 Now, back to the first question:
 >
 > My understanding is that `allow_migrate(db, app_label)` is equiavlent to
 `any(allow_migrate(db, app_label, model_name) for model_name in
 get_model_names(app_label))`, where `get_model_names` is a generator for
 retrieving all the names of all the models inside an app.
 >
 > What I'm still a little confused about is:
 > 1) Why not keep the strict requirement and write the code like the above
 loop? Requiring each statement to be for one model?
 > note: I can easily make that my implementation inside allow_migrate so
 it's not that  this isn't doable.
 >

 I think the current API is a better reflection of the decisions needed to
 be made, and so gives better hints to the authors of routers.

 As an example: Suppose I have an app which has several models, but only
 one of them, say `ModelA`, is stored on database `dbA`. If the API
 requires a model name as you suggest, the natural thing for me to do is
 something like
 {{{
     def allow_migrate(self, db, app_label, model_name):
         if app_label==my_app_label:
             return ((db=='dbA') == (model_name=='modela'))
         else:
             return None
 }}}
 I might be surprised to find out that this allows all `RunPython` and
 `RunSQL` operations in migrations in the app on `dbA`, which is a
 consequence of your suggestion. On the other hand, the current API tells
 me explicitly: There are cases when you need to decide without reference
 to a specific model, where the closest general hint we can give the router
 is the app label.

 On second thought, though, it may be worth reconsidering if we want the
 reply for the `makemigrations` case and the reply for the `RunSQL` case to
 always be the same. In the specific example I just gave, we probably
 don't, and it would be served better if `makemigrations` implemented the
 loop instead of calling the no-model version, or at least, gave a hint
 that this call is asking about the need to run a consistency check, and
 not about the need to change the database.

 I guess I'm replying to [comment:9 Tim]'s question about going forward
 with "we should probably be adding a hint to the call in makemigrations".
 I'm not sure if we should backport that fix to 1.10.x, but I think that is
 an option too, since this would be a fix to a new feature.

--
Ticket URL: <https://code.djangoproject.com/ticket/27200#comment:10>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/064.e3459a6098ae4d872acda363421e3719%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to