I’ve started this discussion to get feedback for my proposal for the project: Adding Enhanced Shell Plus Functionality to Django Core. I am glad this is being implemented this summer, as I myself have been struggling with this. This functionality will make it very convenient to do some quick tests.
I have been studying django-extensions and their implementation of shell_plus.
My background: I am a final year undergrad student in computer science and have been working with Django for 4 years professionally, started contributing last year.
Based on my study it seems quite straightforward and simple to implement.
- It brings a list of all app configs to check the list of names of apps and their respective models.
- Then it checks if there are any models specified by the user or the developer in the " dont_load" variable.
- Once the “load_models” dictionary gets all the model names, it is sent for checking for any alias names for models.
- Now every model to be imported is stored in a dictionary.
- This dictionary goes through a CollisionResolvingRunner which checks if there are any conflicts in the names of the models of any apps anywhere.
- This function is called by the handle method in management/command/shell_plus.
- Once the function is called exec command is used to import the list of models in the shell.
There are also multiple checks for mongoengine and to use document_registry if mongoengine is being used.
We can modify the Django shell command to follow a similar way of working to import all models in the shell automatically. But please tell me if there is any catch to this, that I might be missing.
Question: Are we planning to add this functionality with our updated shell, that certain specified models are not imported and every model other than that list is imported?
It’ll be great to know your thoughts on this one @adamchainz
Great to hear from you. I think you’ve understood the
shell_plus implementation correctly.
One thing to beware of though is that it’s not particularly well-designed. It seems to have grown through accepting all PR’s. For example the mongoengine functionality is niche and not something we’d want to add to Django. Rather we’d want to provide a hook - as I wrote on the wiki, perhaps a doucmented path to subclass the
shell command and override a method.
I also think we don’t want to have “collision resolvers”. We should pick one method, and stick with that. IMO the most natural would be “first model with a given name wins, in
INSTALLED_APPS order”. This is the same way Django handles other name collisions, like if two apps have management commands with the same name.
Anyone who wants a different way of handling collisions could follow the override methodology.
Perhaps one thing we could add is - import every models module by its full path (e.g.
example.core.models) and then import models in app order, first name wins. This way if there’s a collision, the full path is still imported e.g.
Another thing I’d like to drop from the django-extensions module is the printing of every imported model. This is too verbose and can fill up the terminal screen. I think we could just say “auto-imported names”, if we display any output at all.
I think again this functionality is niche and we shouldn’t include it. Users could again do this with an override. I doubt it’s common to want to not import some models - the imports don’t take any significant amount of time because Django already has to load the model classes.
One challenge of this project would be making all shells use this functionality. There are examples enough in the
shell_plus implementation but the code has many extra features that we’d be ignoring.
Hope this helps and looking forward to your proposal. I’m happy to answer further questions!
I’m fine if it’s removed by default, as long as there’s an option to have it printed. I find it extremely useful to identify which model has been imported when working with a project with model name conflicts.
Thanks @adamchainz for the reply, this will help me a lot to form a better proposal.