Enables one-line installation of Django packages by injecting code in the right places.
Project description
Indjections
This project enables one-line installation of Django packages by injecting code in the right places.
Installation
Install using pip
:
pip install indjections
or, if using pipenv:
pipenv install indjections --dev
Add 'indjections'
to your INSTALLED_APPS
setting.
INSTALLED_APPS = [
...
'indjections',
]
Example
By default, indjections
assumes your TOML file is a Pipfile in the
project root. For example, say your Pipfile has 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 indject
This will auto-insert code into settings.py
, urls.py
, and base.html
as described by the package's documentation. For example, for django-hijack
, the following
snippet is added to settings.py
(as described in the documentation):
### block: django-hijack ####
INSTALLED_APPS += ['hijack', 'compat']
### endblock: django-hijack ####
Moreover, if you remove this package from your project's Pipfile and rerun python manage.py indject
,
then indjections
will search for ### block: django-hijack ####
/### endblock: django-hijack ####
and delete this text.
Note that indjections
assumes that base.html
is
the Django admin base.html
and is located at your project root's templates/admin/base.html
.
If you want to use another base.html
, you can add a setting to your project's settings.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's settings.py
:
INDJECTIONS_SETTINGS = {
'INCLUDE_APPS': {
'main': ['djangorestframework'] # any list of installation files
},
}
or
INDJECTIONS_SETTINGS = {
'EXCLUDE_APPS': {
'main': ['djangorestframework'] # any list of installation files
},
}
If both INCLUDE_APPS
and EXCLUDE_APPS
are specified, an exception will be raised.
Q&A
What if I want to modify the inserted code?
You have two options:
- If you change
### block: django-hijack ####
to### block: django-hijack/lock ####
, theninjections
will not reinsert code ifpython manage.py indject
is run again. However, if the package is removed from the TOML file, thenindjections
will delete the block even iflock
appears in the block header. indjections
installation files are regular Python modules. If you create a custom installation file,indjections
will look for custom installers in thecustom_installers
directory 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 defaultindjections
version will be ignored.
What if I don't use pipenv?
The packages can be defined with any TOML file. For example, if you use poetry,
then add the following to your project's settings.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. indjections
is 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 to Cookiecutter Django.
I didn't love the cookiecutter approach, so I wrote indjections
as an alternative.
Cookiecutter Django is 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).
indjections
is a bottom up approach i.e., you can do the usual django-admin startproject {project_name}
and then let python manage.py indject
insert code in the right places.
How do I create my own installation file?
indjections
looks for a module named indjections.packages.{package_name}
.
This declaratively defines 6 locations in a Django project:
settings
: The bottom of settings.py
as defined by the DJANGO_SETTINGS_MODULE
environment variable.
urls
: The bottom of urls.py
as defined by settings.ROOT_URLCONF
.
base_top
: The very top of base.html
e.g., {% load i18n %}
base_head
: The bottom of the <head>
section in base.html
e.g., custom CSS.
base_body
: The top of the <body>
section in base.html
.
base_finally
: The bottom of the <body>
section in base.html
e.g., Javascript <script>
tags
These 6 sections seem to cover the vast majority of Django package installation requirements.
Additionally, indjections
provides 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 the TOML file
post_hook_delete
: Functions run after deleting code (for each package separately); in other words,
if the package is removed from the TOML file
For example, the installation file for django
might include a post_hook
to 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. app1
consists of models Model1
and Model2
and app2
consists
of models Model3
and Model4
. Moreover, we have an installer called
_simple_print
with 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 in settings.py
:
### block: _simple_print ####
# project level code
print("app1")
print("app1:Model1")
print("app1:Model2")
print("app2")
print("app2:Model3")
print("app2:Model4")
### endblock: _simple_print ####
Note that settings = "print('hello')"
is equivalent to settings = ("print('hello')",)
.
Additional project files may be specified with a variable of the form project_*
.
For example, the following declaration will create a new admin.py
file in the same directory
as settings.ROOT_URLCONF
(i.e., a project's urls.py
file):
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 form app_*
,
which will insert code into app files of the form app_*.py
. Here, the first
element of the tuple variable is at the app level and the second element is
at the model level. For example, say the installer for djangorestframework
has 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 in app1/serializers.py
:
### block: djangorestframework ####
from rest_framework import serializers
class Model1Serializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Model1
fields = ['field1', 'field2', 'field3']
class Model2Serializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Model2
fields = ['field1', 'field2', 'field3']
### endblock: djangorestframework ####
and the equivalent insertion in app2/serializers.py
.
Finally, to see the full list of app and model inspection variables, run the following in the console:
from indjections.core import get_app_and_model_data
print(get_app_and_model_data())
Bonus Example: Configuring React.js with Django
After parsing the relevant TOML file,
indjections
looks for the equivalent file name in indjections.packages.{package_name}
. If it
finds the file, the installation procedure begins.
But note that the string reference found in the TOML file does not actually 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, indjections
ships
with a _create-react-app.py
installation file. This will automatically execute create-react-app
and add a reasonable set of configurations for a Django project to serve the React.js app's static files. More specifically, the installer:
- Runs
npx create-react-app reactapp
in the project's root directory - Sets
STATICFILES_DIRS
andTEMPLATES
to plug Django into the React app - Sets Django's
autoreload
signal to watch for file changes in the React app; when files change, the React app is rebuilt and the 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.extras
is a special name. By default,
indjections
looks for dev-packages
, packages
, and indjections.extras
.
Supported Packages
Currently Supported
Seeking Contributors for the Following Packages
- django-filter
- django-tables2
- djangoql
- django-material-admin
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file indjections-0.0.4.tar.gz
.
File metadata
- Download URL: indjections-0.0.4.tar.gz
- Upload date:
- Size: 22.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/47.3.1 requests-toolbelt/0.9.1 tqdm/4.45.0 CPython/3.7.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ca2f549d466aade8841dcdefeff9fcda39540ef164a75f789deb97aae54e4bcd |
|
MD5 | d002bcc57346cc9a7a3a36fdb6d983d6 |
|
BLAKE2b-256 | ec40e94fc0c42733863877a2dbdd9d4efa2beea38360174915d509296e82d5e9 |
File details
Details for the file indjections-0.0.4-py3-none-any.whl
.
File metadata
- Download URL: indjections-0.0.4-py3-none-any.whl
- Upload date:
- Size: 23.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/47.3.1 requests-toolbelt/0.9.1 tqdm/4.45.0 CPython/3.7.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e99267ece59bc9093772c98b5a95a8529298fa7dd5c56b578dded59f23853d74 |
|
MD5 | 40de4a4105a5c810ad2c50609843a166 |
|
BLAKE2b-256 | 4203e527048960add9894ec605806ca432092bbc8091e498d97ff56cc17601dc |