Hello, Since Django 1.7, `get_user_model()` cannot be called at import time. Django contains a lot of methods that start with `UserModel = get_user_model()` while it would be more natural to declare it as a global variable in the module. This trips up users and the reason why it’s forbidden isn’t obvious.
It's the consequence of two design decisions (which I’m responsible for) in the app-loading refactor. 1. Before Django 1.7, the sequence in which models were loaded could depend on which views were hit in what order after a WSGI process started. That allowed interesting failures mode. For example, a project could randomly fail to load, only in production, because of a circular import error. Throw multithreading into the mix and it could get really exciting. To solve this, the new app-loading system added an explicit `django.setup()` step that imports apps and models in a deterministic order and doesn’t let code interact with the app registry until it’s fully loaded. 2. Django must ensure that relationships between models are set up correctly. Specifically it must guarantee that reverse accessors are added to each model targeted by a foreign key. This guarantee can only be provided once all other models have been imported. There’s been a long string of bugs in this area around 2008 (if memory serves). The new app-loading system took this requirement into account at the design stage and, thanks to the explicit setup, is structurally more robust against such bugs. Because of 2. apps.get_models() raises an exception before all models are imported rather than return an incomplete model. Because of 1. Django gives very little control on what happens up to this point. However, in many cases, it doesn’t matter whether the model is fully constructed or not. In the use case I described in my introduction, the code only needs a reference to the model class at import time; that reference won’t be used until run time, after the app-loading process has completed. (Performing SQL queries through the ORM at import time doesn’t work anyway.) For this reason, I think it would make sense to add an API similar to `apps.get_models()`, but that would work while app-loading is still in progress. It would make no guarantees about the functionality of the class it returns until app-loading has completed. I implemented a proof of concept here: https://github.com/django/django/pull/6547. I would appreciate feedback on the following questions: 1. Have you been missing this feature? If it’s needed outside of Django, I must make it a public API. 2. Is it reasonable to expose it as a public API? There’s a risk that StackOverflow will consider it as superior to get_models() because it’s more lax; they'll assume that I put checks in get_models() simply because I like messing with users. 3. Would you prefer adding a kwarg to get_models e.g. apps.get_models(settings.AUTH_USER_MODEL, unsafe=True) or adding a new method like the PR currently does? I’m thinking the former is more user friendly as the functionality is very similar. Thanks, -- Aymeric. -- 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 [email protected]. To post to this group, send email to [email protected]. 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/67450ED7-88CD-49CE-9B63-180EDC033D55%40polytechnique.org. For more options, visit https://groups.google.com/d/optout.
