Package: indjections
IndjectionsThis project enables one-line installation of Django packages by
injecting code in therightplaces.InstallationInstall usingpip:pip install indjectionsor, if usingpipenv:pipenv install indjections --devAdd'indjections'to yourINSTALLED_APPSsetting.INSTALLED_APPS=[...'indjections',]ExampleBy default,indjectionsassumes yourTOMLfile is aPipfilein the
project root.  For example, say yourPipfilehas the following packages:[dev-packages]django-debug-toolbar="*"[packages]djangorestframework="*"django-hijack="*"To install these packages, you just have to run a Django management command:python manage.py indjectThis will auto-insert code intosettings.py,urls.py, andbase.htmlas described by the package's documentation.  For example, fordjango-hijack, the following
snippet is added tosettings.py(as described in thedocumentation):### block: django-hijack ####INSTALLED_APPS+=['hijack','compat']### endblock: django-hijack ####Moreover, if you remove this package from your project'sPipfileand rerunpython manage.py indject,
thenindjectionswill search for### block: django-hijack ####/### endblock: django-hijack ####and delete this text.Note thatindjectionsassumes thatbase.htmlis
the Django adminbase.htmland is located at your project root'stemplates/admin/base.html.
If you want to use anotherbase.html, you can add a setting to your project'ssettings.py:INDJECTIONS_SETTINGS={'BASE_HTML':os.path.join(BASE_DIR,'templates','custom_base.html')}In some cases, a package installer might insert code at the app and model level (see the
discussion below for more detail).  By default, all apps and models in the project are included.
(Obviously, this won't impact third party packages in any way.)  To include/exclude a subset,
you can add a setting to your project'ssettings.py:INDJECTIONS_SETTINGS={'INCLUDE_APPS':{'main':['djangorestframework']# any list of installation files},}orINDJECTIONS_SETTINGS={'EXCLUDE_APPS':{'main':['djangorestframework']# any list of installation files},}If bothINCLUDE_APPSandEXCLUDE_APPSare specified, an exception will be raised.Q&AWhat if I want to modify the inserted code?You have two options:If you change### block: django-hijack ####to### block: django-hijack/lock ####,
theninjectionswill not reinsert code ifpython manage.py indjectis run again.
However, if the package is removed from theTOMLfile, thenindjectionswill delete the block even iflockappears in the block header.indjectionsinstallation files are regular Python modules.  If you create a
custom installation file,indjectionswill look for custom installers in thecustom_installersdirectory of your project's root directory.  For example, if
you want to create a custom installer fordjangorestframework, you just add a
file called{project_root_directory}/custom_installers/djangorestframework.py.
Then this version will be used and the defaultindjectionsversion will be
ignored.What if I don't use pipenv?The packages can be defined withanyTOMLfile.  For example, if you usepoetry,
then add the following to your project'ssettings.py:INDJECTIONS_SETTINGS={'TOML_FILE':os.path.join(BASE_DIR,'pyproject.toml'),'TOML_KEYS':["tool.poetry.dependencies","tool.poetry.dev-dependencies"],}Does this package run anything in production?No.indjectionsis only used during development to help with Django configurations
and project setup.Why do I need another package?I got tired of installing packages by hand.  This project has a similar goal toCookiecutter Django.
I didn't love the cookiecutter approach, so I wroteindjectionsas an alternative.Cookiecutter Djangois a top down approach where packages are all bundled together.
So if you don't like something, you need to spend time removing code (or writing your own cookiecutter).indjectionsis a bottom up approach i.e., you can do the usualdjango-admin startproject {project_name}and then letpython manage.py indjectinsert code in the right places.How do I create my own installation file?indjectionslooks for a module namedindjections.packages.{package_name}.
This declaratively defines 6 locations in a Django project:settings: The bottom ofsettings.pyas defined by theDJANGO_SETTINGS_MODULEenvironment variable.urls: The bottom ofurls.pyas defined bysettings.ROOT_URLCONF.base_top: The very top ofbase.htmle.g.,{% load i18n %}base_head: The bottom of the<head>section inbase.htmle.g., custom CSS.base_body: The top of the<body>section inbase.html.base_finally: The bottom of the<body>section inbase.htmle.g., Javascript<script>tagsThese 6 sections seem to cover the vast majority of Django package installation requirements.Additionally,indjectionsprovides 4 hooks:pre_hook: Functions run before inserting code (for each package separately)post_hook: Functions run after inserting code (for each package separately)pre_hook_delete: Functions run before deleting code (for each package separately); in other words,
if the package is removed from theTOMLfilepost_hook_delete: Functions run after deleting code (for each package separately); in other words,
if the package is removed from theTOMLfileFor example, the installation file fordjangomight include apost_hookto copy Django admin template files to the project root directory.The 6 locations also support insertions of app and model level code.  These are
specified as a tuple, where the first parameter is at the project level, the second
at the app level, and the third at the model level.  For example, say our project
has two apps.app1consists of modelsModel1andModel2andapp2consists
of modelsModel3andModel4.  Moreover, we have an installer called_simple_printwith the following content:settings=('\n# project level code','\nprint("{label}")',# "label" is a Django name at the app level'\nprint("{app_label}:{object_name}")\n',# "app_label" and "object_name" are at the model level)This produces the following text insettings.py:### block: _simple_print ##### project level codeprint("app1")print("app1:Model1")print("app1:Model2")print("app2")print("app2:Model3")print("app2:Model4")### endblock: _simple_print ####Note thatsettings = "print('hello')"is equivalent tosettings = ("print('hello')",).Additional project files may be specified with a variable of the formproject_*.
For example, the following declaration will create a newadmin.pyfile in the same directory
assettings.ROOT_URLCONF(i.e., a project'surls.pyfile):project_admin=('\n# project level code','\nprint("{label}")',# "label" is a Django name at the app level'\nprint("{app_label}:{object_name}")\n',# "app_label" and "object_name" are at the model level)urls="from .admin import *"Finally, installation files can have variables of the formapp_*,
which will insert code into app files of the formapp_*.py.  Here, the first
element of the tuple variable is at theapplevel and the second element is
at themodellevel.  For example, say the installer fordjangorestframeworkhas the following content:app_serializers=("""from rest_framework import serializers""","""class{object_name}Serializer(serializers.HyperlinkedModelSerializer):class Meta:model ={object_name}fields ={field_names}""")This will produce the following inapp1/serializers.py:### block: djangorestframework ####fromrest_frameworkimportserializersclassModel1Serializer(serializers.HyperlinkedModelSerializer):classMeta:model=Model1fields=['field1','field2','field3']classModel2Serializer(serializers.HyperlinkedModelSerializer):classMeta:model=Model2fields=['field1','field2','field3']### endblock: djangorestframework ####and the equivalent insertion inapp2/serializers.py.Finally, to see the full list of app and model inspection variables, run
the following in the console:fromindjections.coreimportget_app_and_model_dataprint(get_app_and_model_data())Bonus Example: ConfiguringReact.jswith DjangoAfter parsing the relevantTOMLfile,indjectionslooks for the equivalent file name inindjections.packages.{package_name}.  If it
finds the file, the installation procedure begins.But note that the string reference found in theTOMLfile
doesnotactually need to be a Python package.  Take the following example:[dev-packages]django-debug-toolbar="*"[packages]djangorestframework="*"django-hijack="*"[indjections.extras]_create-react-app="*"There is no Python package called_create-react-app.  However,indjectionsships
with a_create-react-app.pyinstallation file.  This will automatically executecreate-react-appand add a reasonable set of configurations for a Django project to serve theReact.jsapp's static files.  More specifically, the installer:Runsnpx create-react-app reactappin the project's root directorySetsSTATICFILES_DIRSandTEMPLATESto plug Django into the React appSets Django'sautoreloadsignal to watch for file changes in the React app; when files change,
the React app is rebuiltandthe Django server restarts.Of course, this might not be the optimal setup for your needs, but a) it works out of the box and b)
it's a good starting point for customization.By the way,indjections.extrasis a special name.  By default,indjectionslooks fordev-packages,packages, andindjections.extras.Supported PackagesCurrently Supporteddjango-debug-toolbardjangorestframeworkdjango-hijackdjango-allauthdjango-cors-headersSeeking Contributors for the Following Packagesdjango-filterdjango-tables2djangoqldjango-material-admin