File: shell_plus.rst

package info (click to toggle)
python-django-extensions 4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,820 kB
  • sloc: python: 18,601; javascript: 7,354; makefile: 108; xml: 17
file content (455 lines) | stat: -rw-r--r-- 14,927 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
shell_plus
==========

:synopsis: Django shell with autoloading of the apps database models and subclasses of user-defined classes.


Interactive Python Shells
-------------------------

There is support for three different types of interactive python shells.

IPython::

  $ ./manage.py shell_plus --ipython


bpython::

  $ ./manage.py shell_plus --bpython


ptpython::

  $ ./manage.py shell_plus --ptpython


Python::

  $ ./manage.py shell_plus --plain

It is possible to directly add command line arguments to the underlying Python shell using ``--``::

  $ ./manage.py shell_plus --ipython -- --profile=foo


The default resolution order is: ptpython, bpython, ipython, python.

You can also set the configuration option SHELL_PLUS to explicitly specify which version you want.

::

  # Always use IPython for shell_plus
  SHELL_PLUS = "ipython"


It is also possible to use `IPython Notebook`_, an interactive Python shell which
uses a web browser as its user interface, as an alternative shell::

    $ ./manage.py shell_plus --notebook

Or with JupyterLab (a more feature-rich variant of Jupyter Notebook)::

    $ ./manage.py shell_plus --lab

In addition to being savable, IPython Notebooks can be updated (while running) to reflect changes in a Django application's code with the menu command `Kernel > Restart`.


Configuration
-------------

Sometimes, models from your own apps and other people's apps have colliding names,
or you may want to completely skip loading an app's models. Here are some examples of how to do that.

Note: These settings are only used inside shell_plus and will not affect your environment.

::

  # Rename the automatic loaded module Messages in the app blog to blog_messages.
  SHELL_PLUS_MODEL_ALIASES = {'blog': {'Messages': 'blog_messages'},}

::

  # Prefix all automatically loaded models in the app blog with myblog.
  SHELL_PLUS_APP_PREFIXES = {'blog': 'myblog',}

::

  # Dont load the 'sites' app, and skip the model 'pictures' in the app 'blog'
  SHELL_PLUS_DONT_LOAD = ['sites', 'blog.pictures']


::

  # Dont load any models
  SHELL_PLUS_DONT_LOAD = ['*']

You can also combine model_aliases and dont_load.
When referencing nested modules, e.g. `somepackage.someapp.models.somemodel`, omit the
package name and the reference to `models`. For example:

::

    SHELL_PLUS_DONT_LOAD = ['someapp.somemodel', ]  # This works
    SHELL_PLUS_DONT_LOAD = ['somepackage.someapp.models.somemodel', ]  # This does NOT work

It is possible to ignore autoloaded modules when using manage.py, like::

  $ ./manage.py shell_plus --dont-load app1 --dont-load app2.module1

Command line parameters and settings in the configuration file are merged, so you can
safely append modules to ignore from the commandline for one-time usage.

Other configuration options include:

::

  # Always use IPython for shell_plus
  SHELL_PLUS = "ipython"


::

  SHELL_PLUS_PRINT_SQL = True

  # Truncate sql queries to this number of characters (this is the default)
  SHELL_PLUS_PRINT_SQL_TRUNCATE = 1000

  # To disable truncation of sql queries use
  SHELL_PLUS_PRINT_SQL_TRUNCATE = None

  # Specify sqlparse configuration options when printing sql queries to the console
  SHELL_PLUS_SQLPARSE_FORMAT_KWARGS = dict(
    reindent_aligned=True,
    truncate_strings=500,
  )

  # Specify Pygments formatter and configuration options when printing sql queries to the console
  import pygments.formatters
  SHELL_PLUS_PYGMENTS_FORMATTER = pygments.formatters.TerminalFormatter
  SHELL_PLUS_PYGMENTS_FORMATTER_KWARGS = {}


::

  # Additional IPython arguments to use
  IPYTHON_ARGUMENTS = []

  IPYTHON_KERNEL_DISPLAY_NAME = "Django Shell-Plus"

  # Additional Notebook arguments to use
  NOTEBOOK_ARGUMENTS = []
  NOTEBOOK_KERNEL_SPEC_NAMES = ["python3", "python"]



Collision resolvers
-------------------
You don't have to worry about inaccessibility of models with conflicting names.

If you have conflicting model names, all conflicts can be resolved automatically.
All models will be available under shell_plus, some of them with intuitive aliases.

This mechanism is highly configurable and you must only set ``SHELL_PLUS_MODEL_IMPORTS_RESOLVER``.
You should set full path to collision resolver class.

All predefined collision resolvers are in ``django_extensions.collision_resolvers`` module. Example::

    SHELL_PLUS_MODEL_IMPORTS_RESOLVER = 'django_extensions.collision_resolvers.FullPathCR'

All collision resolvers searches for models with the same name.

If conflict is detected they decides, which model to choose.
Some of them are creating aliases for all conflicting models.

**Example**

Suppose that we have two apps:

- programming(with models Language and Framework)

- workers(with models Language and Worker)

'workers' app is last in alphabetical order, but suppose that 'programming' app is occurs firstly in ``INSTALLED_APPS``.

Collision resolvers won't change aliases for models Framework and Worker, because their names are unique.
There are several types of collision resolvers:

**LegacyCR**

Default collision resolver. Model from last application in alphabetical order is selected::

    from workers import Language

**InstalledAppsOrderCR**

Collision resolver which selects the first model from INSTALLED_APPS.
You can set your own app priorities list subclassing him and overwriting ``APP_PRIORITIES`` field.

This collision resolver will select a model from the first app on this list.
If both app's are absent on this list, resolver will choose a model from the first app in alphabetical order::

    from programming import Language

**FullPathCR**

Collision resolver which transform full model name to alias by changing dots to underscores.
He also removes 'models' part of alias, because all models are in models.py files.

Model from last application in alphabetical order is selected::

    from programming import Language (as programming_Language)
    from workers import Language, Language (as workers_Language)

**AppNamePrefixCR**

Collision resolver which transform pair (app name, model_name) to alias ``{app_name}_{model_name}``.
Model from last application in alphabetical order is selected.

Result is different than FullPathCR, when model has app_label other than current app::

    from programming import Language (as programming_Language)
    from workers import Language, Language (as workers_Language)

**AppNameSuffixCR**

Collision resolver which transform pair (app name, model_name) to alias ``{model_name}_{app_name}``

Model from last application in alphabetical order is selected::

    from programming import Language (as Language_programming)
    from workers import Language, Language (as Language_workers)

**AppNamePrefixCustomOrderCR**

Collision resolver which is mixin of AppNamePrefixCR and InstalledAppsOrderCR.

In case of collisions he sets aliases like AppNamePrefixCR, but sets the default model using InstalledAppsOrderCR::

    from programming import Language, Language (as programming_Language)
    from workers import Language (as workers_Language)

**AppNameSuffixCustomOrderCR**

Collision resolver which is a mixin of AppNameSuffixCR and InstalledAppsOrderCR.

In case of collisions he sets aliases like AppNameSuffixCR, but sets the default model using InstalledAppsOrderCR::

    from programming import Language, Language (as Language_programming)
    from workers import Language (as Language_workers)

**FullPathCustomOrderCR**

Collision resolver which is a mixin of FullPathCR and InstalledAppsOrderCR.

In case of collisions he sets aliases like FullPathCR, but sets the default model using InstalledAppsOrderCR::

    from programming import Language, Language (as programming_Language)
    from workers import Language (as workers_Language)

**AppLabelPrefixCR**

Collision resolver which transform pair (app_label, model_name) to alias ``{app_label}_{model_name}``

This is very similar to ``AppNamePrefixCR`` but this may generate shorter names in the case of apps nested
into several namespace (like Django's auth app)::

    # with AppNamePrefixCR
    from django.contrib.auth.models import Group (as django_contrib_auth_Group)

    # with AppLabelPrefixCR
    from django.contrib.auth.models import Group (as auth_Group)

**AppLabelSuffixCR**

Collision resolver which transform pair (app_label, model_name) to alias ``{model_name}_{app_label}``

Similar idea as the above, but based on ``AppNameSuffixCR``::

    # with AppNamePrefixCR
    from django.contrib.auth.models import Group (as Group_django_contrib_auth)

    # with AppLabelSuffixCR
    from django.contrib.auth.models import Group (as Group_auth)


Writing your custom collision resolver
--------------------------------------

You can customize models import behaviour by subclassing one of the abstract collision resolvers:


**PathBasedCR**

Abstract resolver which transforms full model name into alias.
To use him you need to overwrite transform_import function
which should have one parameter.

It will be a full model name. It should return valid alias as a str instance.

**AppNameCR**

Abstract collision resolver which transform pair (app name, model_name) to alias by changing dots to underscores.

You must define ``MODIFICATION_STRING`` which should be string to format with two keyword arguments:
app_name and model_name. For example: ``{app_name}_{model_name}``.

Model from last application in alphabetical order is selected.

You can mix PathBasedCR or AppNameCR with InstalledAppsOrderCR, but InstalledAppsOrderCR should be the second base class.

**BaseCR**

Abstract base collision resolver. All collision resolvers needs to inherit from this class.

To write a custom collision resolver you need to overwrite the resolve_collisions function.
It receives ``Dict[str, List[str]]`` where key is model name and values are full model names
(full model name means: module + model_name).

You should return ``Dict[str, str]``, where key is model name and value is full model name.

Import Subclasses
-------------------
If you want to load automatically all project subclasses of some base class,
you can achieve this by setting ``SHELL_PLUS_SUBCLASSES_IMPORT`` option.

It must be a list of either classes or strings containing paths to these classes.

For example, if you want to load all your custom managers then you should provide::

    from django.db.models import Manager
    SHELL_PLUS_SUBCLASSES_IMPORT = [Manager]

Then shell_plus will load all your custom managers::

    # Shell Plus Subclasses Imports
    from utils.managers import AbstractManager
    from myapp.managers import MyCustomManager
    from somewhere.else import MyOtherManager
    # django.db.models.Manager is not loaded because only project classes are.

By default, all subclasses of your base class from all projects modules will be loaded.

You can exclude some modules and all their submodules by passing ``SHELL_PLUS_SUBCLASSES_IMPORT_MODULES_BLACKLIST`` option::

    SHELL_PLUS_SUBCLASSES_IMPORT_MODULES_BLACKLIST = ['utils', 'somewhere.else']

Elements of this list must be strings containing full modules paths.
If these modules are excluded only ``MyCustomManager`` from ``myapp.managers`` will be loaded.

If you are using ``SHELL_PLUS_SUBCLASSES_IMPORT`` shell_plus loads all project modules for finding subclasses.

Sometimes it can lead to some errors(for example when we have an old unused module which contains syntax errors).

Excluding these modules can help avoid shell_plus crashes in some situations.
It is recommended to exclude all ``setup.py`` files.

IPython Notebook
----------------
There are two settings that you can use to pass your custom options to the IPython
Notebook in your Django settings.

The first one is ``NOTEBOOK_ARGUMENTS`` that can be used to hold those options that available via::

    $ ipython notebook -h

For example::

    NOTEBOOK_ARGUMENTS = [
        '--ip', 'x.x.x.x',
        '--port', 'xx',
    ]

Another one is ``IPYTHON_ARGUMENTS`` that for those options that available via::

    $ ipython -h

The Django settings module and database models are auto-loaded into the
interactive shell's global namespace also for IPython Notebook.

Auto-loading is done by a custom IPython extension which is activated by
default by passing the
``--ext django_extensions.management.notebook_extension``
argument to the Notebook.  If you need to pass custom options to the IPython
Notebook, you can override the default options in your Django settings using
the ``IPYTHON_ARGUMENTS`` setting.  For example::

    IPYTHON_ARGUMENTS = [
        '--ext', 'django_extensions.management.notebook_extension',
        '--ext', 'myproject.notebook_extension',
        '--debug',
    ]

To activate auto-loading, remember to either include the django-extensions' default
notebook extension or copy its auto-loading code into your own extension.

Note that the IPython Notebook feature doesn't currently honor the
``--dont-load`` option.

.. _`IPython Notebook`: https://ipython.org/ipython-doc/dev/interactive/htmlnotebook.html



Additional Imports
------------------

In addition to importing the models, you can specify other items to import by default.
These can be specified with the settings ``SHELL_PLUS_IMPORTS``, ``SHELL_PLUS_PRE_IMPORTS`` and ``SHELL_PLUS_POST_IMPORTS``.

The order of import loading is as follows:

 - ``SHELL_PLUS_PRE_IMPORTS``
 - Subclasses (if enabled)
 - Models (if not disabled)
 - Default Django imports (if not disabled)
 - ``SHELL_PLUS_IMPORTS``
 - ``SHELL_PLUS_POST_IMPORTS``

Example for in your ``settings.py`` file:

::

    SHELL_PLUS_IMPORTS = [
        'from module.submodule1 import class1, function2',
        'from module.submodule2 import function3 as another1',
        'from module.submodule3 import *',
        'import module.submodule4',
    ]


These symbols will be available as soon as the shell starts.


Database application signature
------------------------------

If using PostgreSQL the ``application_name`` is set by default to
``django_shell`` to help  identify queries made under shell_plus.


SQL queries
-------------------------

If the configuration option DEBUG is set to True, it is possible to print SQL queries as they're executed in shell_plus like::

  $ ./manage.py shell_plus --print-sql

You can also set the configuration option SHELL_PLUS_PRINT_SQL to omit the above command line option.

::

  # print SQL queries in shell_plus
  SHELL_PLUS_PRINT_SQL = True

Printing SQL queries also comes with the possibility of specifying the maximum amount of characters to display:

  $ ./manage.py shell_plus --print-sql --truncate-sql

`--truncate-sql` accepts an int value starting from 0 (which disables truncation). Defaults to 1000.

You can also set the configuration option SHELL_PLUS_PRINT_SQL_TRUNCATE to omit the above command line option.

::

  # print SQL queries in shell_plus
  SHELL_PLUS_PRINT_SQL_TRUNCATE = None