[](https://pypi.python.org/pypi/django-dynamic-admin-forms/)
[](https://pepy.tech/project/django-dynamic-admin-forms)
# django-dynamic-admin-forms
Add simple interactions to the otherwise static django admin.
[](https://postimg.cc/Yv9ZJdWp)
## Installation
- Install the package via pip:
```pip install django-dynamic-admin-forms```
or via pipenv:
```pipenv install django-dynamic-admin-forms```
- Add the module to `INSTALLED_APPS`:
```python
INSTALLED_APPS = (
...,
'dynamic_admin_forms',
'django.contrib.admin'
...
)
```
Ensure that the `dynamic_admin_forms` comes before the
default `django.contrib.admin` in the list of installed apps,
because otherwise the templates, which are overwritten by `dynamic_admin_forms`
won't be found.
- Ensure that the `dynamic_admin_forms` templates are found via using `APP_DIRS` setting:
```python
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
...
},
]
```
- Run `python manage.py collectstatic` to include this apps Javascript code in your `settings.STATIC_ROOT` directory
## Usage
- Add the `dynamic_admin_forms.DynamicModelAdminMixin` to your admin classes
- Add the `dynamic_admin_forms.urls` to your urls
```python
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("dynamic-admin-form/", include("dynamic_admin_forms.urls")),
]
```
- In addition to the standard `fields` declaration, specify a list of `dynamic_fields`
- For each dynamic field, add a method `get_dynamic_{field_name}_field` to the admin
- Input: `data: Dict[str, Any]` - the cleaned form data
- Output:
- `queryset: Optional[Queryset]` - The values to select from
- `value: Any` - The value, the field should have (must be compatible to the field type)
- `hidden: Bool` - True, if field should be hidden
- A rather non-sensical example:
```python
from django.contrib import admin
from .models import MyModel
from dynamic_admin_forms.admin import DynamicModelAdminMixin
@admin.register(MyModel)
class MyModelAdmin(DynamicModelAdminMixin, admin.ModelAdmin):
fields = ("name", "city")
dynamic_fields = ("city",)
def get_dynamic_city_field(self, data):
# automatically choose first city that matches first letter of name
name = data.get("name")
if not name:
queryset = City.objects.all()
value = data.get("city")
else:
queryset = City.objects.filter(name__startswith=name[0])
value = queryset.first()
hidden = not queryset.exists()
return queryset, value, hidden
```
## How it works
Whenever a dynamic form changes, an event handler makes a request to a special endpoint, which returns new HTML to swap
into the existing form. This new HTML is directly generated by `django.contrib.admin`, so we only have to set the
outerHTML of the correct HTML elements to update the form.
## Limitations
- does not work in conjunction with inlines
- does not validate that the selected value is really part of the original queryset
- if anybody can modify your DOM, they could potentially inject invalid values
- you have to write `Model.clean()` methods to guard against that
- only tested with Django 3.2
## Publishing
This project uses the flit package to publish to PyPI.
Thus publishing should be as easy as running
```
flit publish
```
To publish to TestPyPI use the following ensure that
you have set up your .pypirc as shown [here](https://flit.readthedocs.io/en/latest/upload.html#using-pypirc) and use
the following command:
```
flit publish --repository testpypi
```
## Development
For local development, create a virtual environment
in the `testproj` folder:
```shell
$ cd testproj
$ python3 -m venv .venv
$ source .venv/bin/activate
$ cd ..
$ flit install --symlink
```
Now the package should be available in your virtual environment
and any changes should be directly visible.
Alternatively, simply copy the directory `dynamic_admin_forms`
into any normal django project, so that the python interpreter
finds the local version instead of the installed (old) version.
## Running E2E tests
To run end-to-end tests locally:
```shell
$ cd testproj
$ python manage.py runserver 0.0.0.0:8000 & # start server
$ python manage.py loaddata fixtures/fixtures-dev.json
$ cd ../e2e
$ yarn install # or npm install (only needed first time)
$ yarn cypress # or npm run cypress
```
## Changelog
- 0.1.8: Improve support for select2 widgets used by Jazzmin
- 0.1.7: Improve Jazzmin support and forms with file fields
- 0.1.6: Support dynamic fields for custom form fields
- 0.1.5: Jazzmin "support"
- 0.1.4: README fixes
- 0.1.3: Change Demo-GIF hosting
- 0.1.2: README fixes
- 0.1.1: README fixes
- 0.1.0: Initial release