Skip to content

Commit

Permalink
v3.0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
GitRon committed Jun 20, 2024
1 parent 851dd53 commit b3fe11f
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 175 deletions.
162 changes: 0 additions & 162 deletions .ambient-package-update/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,168 +29,6 @@
has_migrations=False,
readme_content=ReadmeContent(
tagline="Add simple interactions to the otherwise static django admin.",
content="""# django-dynamic-admin-forms
Add simple interactions to the otherwise static django admin.
[![demo.gif](https://i.postimg.cc/YCf7LV2m/demo.gif)](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 = (
...,
'django_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 `django_dynamic_admin_forms.DynamicModelAdminMixin` to your admin classes
- Add the `django_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("django_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 django_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
## 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, 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
```
""",
custom_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 = (
...,
'django_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
""",
),
supported_django_versions=SUPPORTED_DJANGO_VERSIONS,
supported_python_versions=SUPPORTED_PYTHON_VERSIONS,
Expand Down
128 changes: 128 additions & 0 deletions .ambient-package-update/templates/snippets/content.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# django-dynamic-admin-forms

Add simple interactions to the otherwise static django admin.

[![demo.gif](https://i.postimg.cc/YCf7LV2m/demo.gif)](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 = (
...,
'django_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 `django_dynamic_admin_forms.DynamicModelAdminMixin` to your admin classes
- Add the `django_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("django_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 django_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

## 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, 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
```
36 changes: 36 additions & 0 deletions .ambient-package-update/templates/snippets/installation.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## 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 = (
...,
'django_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
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

**3.0.3**
* Restructured Readme content

**3.0.2**
* Internal updates via `ambient-package-update`

Expand Down
35 changes: 24 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,29 +142,42 @@ $ yarn install # or npm install (only needed first time)
$ yarn cypress # or npm run cypress
```


## Installation

- Install the package via pip:

`pip install django-dynamic-admin-forms`

or via pipenv:
`pip install django-dynamic-admin-forms`

`pipenv install django-dynamic-admin-forms`
or via pipenv:

- Add module to `INSTALLED_APPS` within the main django `settings.py`:
`pipenv install django-dynamic-admin-forms`

````
- Add the module to `INSTALLED_APPS`:
```python
INSTALLED_APPS = (
...
...,
'django_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

## Contribute

Expand Down
Loading

0 comments on commit b3fe11f

Please sign in to comment.