3.6. Django Extensions

One of the libraries included in this project is django-extensions (https://django-extensions.readthedocs.io/). It has a number of useful extension to the manage.py module provided by Django. The extensions used by this project are:

Model Relationships

This extention produces a graph of the tables in the application and their interrelationships. More details are provided in Model (Table) Relationships below.

Model vs. Database Differences

This extension produces output that shows if your models and database schema are in sync. If not, it outputs the SQL statements that will put it in sync. See Model vs. Database Differences below for an example.

Show all URLs

This extension is useful to show all defined URL’s, the view associates with each URL, and the name attached to that URL. See Show URLs below.

Dump Script

A extension is available to dump the entire schema and all data to a Python script. See Dump Script below.

Dump Data

The dump data command can dump the contents of a table in a format suitable as a fixture file. See Dump Data below.

3.6.1. Model (Table) Relationships

The extension “graph-models” generates a graph showing all the models (tables) defined and how they are related. Each foreign key is shown with an arrow pointing to the source table and field. The arrows indicate if the relationship is one-to-one, one-to-many or many-to-many.

A graph for this project can be downloaded from

Inventory and Authorization Models

This extension generatss a “.dot” file that is interpreted by the GraphViz library (see GraphViz documentation ).

By also loading the library PyGraphViz (see PyGraphViz documentation) the ” .dot” file generated above is converted into a format usable for humans.

The command used to make all this happen is:

./manage.py graph_models fpiweb auth -g -o InventoryProjectModelsGrouped.pdf

3.6.2. Model vs. Database Differences

This extension shows any difference between the models and the database.

The command:

./manage.py sqldiff -a -e

produced this output:

BEGIN;
-- Application: fpiweb
-- Model: Activity
DROP INDEX "fpiweb_activity_BoxNumber_10d7ca04_like";
-- Model: Constraints
ALTER TABLE "fpiweb_constraints"
        ADD CONSTRAINT "fpiweb_constraints_constraint_name_0fa0e463_uniq" UNIQUE ("constraint_name");
CREATE INDEX "fpiweb_constraints_constraint_name_0fa0e463_like"
        ON "fpiweb_constraints" ("constraint_name" varchar_pattern_ops);
COMMIT;

This command reported the result as text rather than SQL.

./manage.py sqldiff -a -e -t

Results:

+ Application: fpiweb
|-+ Differences for model: Activity
|--+ field 'fpiweb_activity_BoxNumber_10d7ca04_like' INDEX defined in database schema but missing in model
|-+ Differences for model: Constraints
|--+ field 'constraint_name' UNIQUE named 'fpiweb_constraints_constraint_name_0fa0e463_uniq' defined in model but missing in database
|--+ field 'constraint_name' INDEX named 'fpiweb_constraints_constraint_name_0fa0e463_like' defined in model but missing in database

3.6.3. Show URLs

The “show_urls” command is not as polished as the other commands although it still produces useful output.

The command:

./manage.py show_urls

produces output like this (partial):

/       fpiweb.views.LoginView
/fpiweb/        fpiweb.views.IndexView  fpiweb:index
/fpiweb/about/  fpiweb.views.AboutView  fpiweb:about
/fpiweb/activity/download/      fpiweb.views.ActivityDownloadView       fpiweb:download_activities
/fpiweb/box/<int:pk>/   fpiweb.views.BoxDetailsView     fpiweb:box_details
/fpiweb/box/<int:pk>/edit/      fpiweb.views.BoxEditView        fpiweb:box_edit
/fpiweb/box/<int:pk>/empty/     fpiweb.views.BoxEmptyMoveView   fpiweb:box_empty
/fpiweb/box/<int:pk>/empty_move/        fpiweb.views.BoxEmptyMoveView   fpiweb:box_empty_move
/fpiweb/box/<int:pk>/fill/      fpiweb.views.BoxEmptyMoveView   fpiweb:box_fill
/fpiweb/box/<int:pk>/move/      fpiweb.views.BoxMoveView        fpiweb:box_move
/fpiweb/box/box<int:number>/    fpiweb.views.BoxScannedView     fpiweb:box_scanned
/fpiweb/box/box_form/   fpiweb.views.BoxItemFormView    fpiweb:box_form
/fpiweb/box/new/<str:box_number>/       fpiweb.views.BoxNewView fpiweb:box_new
/fpiweb/build_pallet/   fpiweb.views.BuildPalletView    fpiweb:build_pallet
/fpiweb/build_pallet/   fpiweb.views.BuildPalletView    fpiweb:build_pallet
/fpiweb/build_pallet/<int:box_pk>/      fpiweb.views.BuildPalletView    fpiweb:build_pallet_add_box
/fpiweb/build_pallet/<str:box_number>/  fpiweb.views.BuildPalletView    fpiweb:build_pallet_add_box
/fpiweb/constraint/add/ fpiweb.views.ConstraintCreateView       fpiweb:constraint_new
/fpiweb/constraint/delete/<int:pk>/     fpiweb.views.ConstraintDeleteView       fpiweb:constraint_delete
/fpiweb/constraint/edit/<int:pk>/       fpiweb.views.ConstraintUpdateView       fpiweb:constraint_update
/fpiweb/constraints/    fpiweb.views.ConstraintsListView        fpiweb:constraints_view
/fpiweb/index/  fpiweb.views.IndexView  fpiweb:index
/fpiweb/loc_bin/        fpiweb.views.LocBinListView     fpiweb:loc_bin_view
/fpiweb/loc_bin/add/    fpiweb.views.LocBinCreateView   fpiweb:loc_bin_new
/fpiweb/loc_bin/delete/<int:pk>/        fpiweb.views.LocBinDeleteView   fpiweb:loc_bin_delete
/fpiweb/loc_bin/edit/<int:pk>/  fpiweb.views.LocBinUpdateView   fpiweb:loc_bin_update
/fpiweb/loc_row/        fpiweb.views.LocRowListView     fpiweb:loc_row_view
/fpiweb/loc_row/add/    fpiweb.views.LocRowCreateView   fpiweb:loc_row_new
/fpiweb/loc_row/delete/<int:pk>/        fpiweb.views.LocRowDeleteView   fpiweb:loc_row_delete
/fpiweb/loc_row/edit/<int:pk>/  fpiweb.views.LocRowUpdateView   fpiweb:loc_row_update
/fpiweb/loc_tier/       fpiweb.views.LocTierListView    fpiweb:loc_tier_view
/fpiweb/loc_tier/add/   fpiweb.views.LocTierCreateView  fpiweb:loc_tier_new
/fpiweb/loc_tier/delete/<int:pk>/       fpiweb.views.LocTierDeleteView  fpiweb:loc_tier_delete
/fpiweb/loc_tier/edit/<int:pk>/ fpiweb.views.LocTierUpdateView  fpiweb:loc_tier_update
/fpiweb/login/  fpiweb.views.LoginView  fpiweb:login
/fpiweb/logout/ fpiweb.views.LogoutView fpiweb:logout
/fpiweb/maintenance/    fpiweb.views.MaintenanceView    fpiweb:maintenance
/fpiweb/manual_add_box/ fpiweb.views.ManualNewBoxView   fpiweb:manual_add_box
/fpiweb/manual_box_status/      fpiweb.views.ManualBoxStatusView        fpiweb:manual_box_status
...

The output has the URL, the view it invokes, and the name attached to it. The output has a tab character between each field so it could be imported into a spreadsheet for easy reference and manipulation. At this point in our development, run the command to get the current list of URL’s.

3.6.4. Dump Script

The “dumpscript” command will dump all the schema and data from the current database into a script. The script can subsequently be used to reload into a database that was just created. The script will create the schema for the application (and other Django tables) and load all the previously known data into it. The advantage of the script vs. a database backup is that the script is completely in python so there are no SQL syntax details get in the way of moving to a different database vendor.

Unfortunately, this extension chokes on our database because we have “time zone aware” data in it. Perhaps we can file an issue with the maintainers and get a fix or workaround.

3.6.5. Dump Data

The “dumpdata” command can be used to create a file suitable for inclusion in the fixtures directory. Once the table has all the desired records and values, use a command similar to the one below.

./manage.py dumpdata  -o pallot.json fpiweb.pallet

This command is an example of dumping the fpiweb pallet table to a file called pallet.json in the current directory. It can then be moved to the fixtures directory or other desired location.

(more Django extensions used by this project)