Setting up pyenv and show default value on confirm add (#7)
Co-authored-by: Thu Trang Pham <thu@joinmodernhealth.com>main
parent
591aa48ba0
commit
209de62c9d
|
|
@ -0,0 +1 @@
|
||||||
|
django-admin-confirm-3.8
|
||||||
1
Makefile
1
Makefile
|
|
@ -5,7 +5,6 @@ test:
|
||||||
coverage run --branch -m pytest
|
coverage run --branch -m pytest
|
||||||
coverage html
|
coverage html
|
||||||
coverage-badge -f -o coverage.svg
|
coverage-badge -f -o coverage.svg
|
||||||
python -m readme_renderer README.md -o /tmp/README.html
|
|
||||||
|
|
||||||
check-readme:
|
check-readme:
|
||||||
python -m readme_renderer README.md -o /tmp/README.html
|
python -m readme_renderer README.md -o /tmp/README.html
|
||||||
|
|
|
||||||
34
README.md
34
README.md
|
|
@ -6,6 +6,8 @@ AdminConfirmMixin is a mixin for ModelAdmin to add confirmations to change, add
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
It can be configured to add a confirmation page on ModelAdmin upon:
|
It can be configured to add a confirmation page on ModelAdmin upon:
|
||||||
|
|
@ -126,6 +128,38 @@ Your appreciation is also very welcome :) Feel free to:
|
||||||
- star the project
|
- star the project
|
||||||
- open an issue just to share your thanks
|
- open an issue just to share your thanks
|
||||||
|
|
||||||
|
### Local Development Setup
|
||||||
|
|
||||||
|
Install pyenv
|
||||||
|
Install python 3.8
|
||||||
|
|
||||||
|
Create virtualenv via pyenv
|
||||||
|
|
||||||
|
```
|
||||||
|
pyenv vituralenv 3.8 django-admin-confirm-3.8
|
||||||
|
```
|
||||||
|
|
||||||
|
Now your terminal should have `(django-admin-confirm-3.8)` prefix, because `.python-version` should have auto switch your virtual env
|
||||||
|
|
||||||
|
Run migrations and create a superuser and run the server
|
||||||
|
|
||||||
|
```
|
||||||
|
./tests/manage.py migrate
|
||||||
|
./tests/manage.py createsuperuser
|
||||||
|
./tests/manage.py runserver
|
||||||
|
```
|
||||||
|
|
||||||
|
You should be able to see the test app at `localhost:8000/admin`
|
||||||
|
|
||||||
|
Running tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
make test
|
||||||
|
tox
|
||||||
|
```
|
||||||
|
|
||||||
|
Testing new changes on test project:
|
||||||
|
|
||||||
## Feature List
|
## Feature List
|
||||||
|
|
||||||
This is a list of features which could potentially be added in the future. Some of which might make more sense in their own package.
|
This is a list of features which could potentially be added in the future. Some of which might make more sense in their own package.
|
||||||
|
|
|
||||||
|
|
@ -134,14 +134,16 @@ class AdminConfirmMixin:
|
||||||
changed_data = {}
|
changed_data = {}
|
||||||
if form_validated:
|
if form_validated:
|
||||||
if add:
|
if add:
|
||||||
for name in form.changed_data:
|
for name in form.cleaned_data:
|
||||||
new_value = getattr(new_object, name)
|
new_value = getattr(new_object, name)
|
||||||
# Don't consider default values as changed for adding
|
# Don't consider default values as changed for adding
|
||||||
|
default_value = model._meta.get_field(name).get_default()
|
||||||
if (
|
if (
|
||||||
new_value is not None
|
new_value is not None
|
||||||
and new_value != model._meta.get_field(name).default
|
and new_value != default_value
|
||||||
):
|
):
|
||||||
changed_data[name] = [None, new_value]
|
# Show what the default value is
|
||||||
|
changed_data[name] = [str(default_value), new_value]
|
||||||
else:
|
else:
|
||||||
# Parse the changed data - Note that using form.changed_data would not work because initial is not set
|
# Parse the changed data - Note that using form.changed_data would not work because initial is not set
|
||||||
for name, field in form.fields.items():
|
for name, field in form.fields.items():
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
{% if changed_data %}
|
{% if changed_data %}
|
||||||
<div class="changed-data">
|
<div class="changed-data">
|
||||||
<p><b>Confirm Values:</b></p>
|
<p><b>Confirm Values:</b></p>
|
||||||
<table>
|
<table>
|
||||||
<tr><th>Field</th><th>Current Value</th><th>New Value</th></tr>
|
<tr>
|
||||||
|
<th>Field</th>
|
||||||
|
<th>{% if add %} Default {% else %} Current {% endif %}Value</th>
|
||||||
|
<th>New Value</th>
|
||||||
|
</tr>
|
||||||
{% for field, values in changed_data.items %}
|
{% for field, values in changed_data.items %}
|
||||||
<tr><td>{{ field }}</td><td>{{ values.0 }}</td><td>{{ values.1 }}</td></tr>
|
<tr>
|
||||||
|
<td>{{ field }}</td>
|
||||||
|
<td>{{ values.0 }}</td>
|
||||||
|
<td>{{ values.1 }}</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@
|
||||||
</mask>
|
</mask>
|
||||||
<g mask="url(#a)">
|
<g mask="url(#a)">
|
||||||
<path fill="#555" d="M0 0h63v20H0z"/>
|
<path fill="#555" d="M0 0h63v20H0z"/>
|
||||||
<path fill="#4c1" d="M63 0h36v20H63z"/>
|
<path fill="#fe7d37" d="M63 0h36v20H63z"/>
|
||||||
<path fill="url(#b)" d="M0 0h99v20H0z"/>
|
<path fill="url(#b)" d="M0 0h99v20H0z"/>
|
||||||
</g>
|
</g>
|
||||||
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
||||||
<text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
|
<text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
|
||||||
<text x="31.5" y="14">coverage</text>
|
<text x="31.5" y="14">coverage</text>
|
||||||
<text x="80" y="15" fill="#010101" fill-opacity=".3">100%</text>
|
<text x="80" y="15" fill="#010101" fill-opacity=".3">42%</text>
|
||||||
<text x="80" y="14">100%</text>
|
<text x="80" y="14">42%</text>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 904 B |
|
|
@ -1,4 +1,4 @@
|
||||||
[pytest]
|
[pytest]
|
||||||
DJANGO_SETTINGS_MODULE=tests.test_project.settings
|
DJANGO_SETTINGS_MODULE=tests.test_project.settings.test
|
||||||
addopts = --doctest-modules -ra -l --tb=short --show-capture=log --color=yes
|
addopts = --doctest-modules -ra -l --tb=short --show-capture=log --color=yes
|
||||||
testpaths = admin_confirm
|
testpaths = admin_confirm
|
||||||
|
|
@ -1,2 +1,10 @@
|
||||||
Django>=1.7.0
|
Django>=1.7.0
|
||||||
factory-boy~=3.0.1
|
factory-boy~=3.0.1
|
||||||
|
django-admin-confirm~=0.2.1
|
||||||
|
coverage~=5.4
|
||||||
|
pytest~=6.2.2
|
||||||
|
tox~=3.21.4
|
||||||
|
pytest-django~=4.1.0
|
||||||
|
coverage-badge~=1.0.1
|
||||||
|
readme-renderer~=28.0
|
||||||
|
twine~=3.3.0
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
1
setup.py
1
setup.py
|
|
@ -25,5 +25,4 @@ setup(
|
||||||
# ISSUE-4: Ensure that package includes template and css folders
|
# ISSUE-4: Ensure that package includes template and css folders
|
||||||
# list files in MANIFEST.in
|
# list files in MANIFEST.in
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.1.6 on 2021-02-10 00:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('market', '0003_auto_20201108_1717'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventory',
|
||||||
|
name='notes',
|
||||||
|
field=models.TextField(blank=True, default='This is the default', null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -32,3 +32,4 @@ class Inventory(models.Model):
|
||||||
)
|
)
|
||||||
item = models.ForeignKey(to=Item, on_delete=models.CASCADE)
|
item = models.ForeignKey(to=Item, on_delete=models.CASCADE)
|
||||||
quantity = models.PositiveIntegerField(default=0, null=True, blank=True)
|
quantity = models.PositiveIntegerField(default=0, null=True, blank=True)
|
||||||
|
notes = models.TextField(default="This is the default", null=True, blank=True)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ INSTALLED_APPS = [
|
||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
"django.contrib.messages",
|
"django.contrib.messages",
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
"tests.market",
|
"market",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|
@ -50,7 +50,7 @@ MIDDLEWARE = [
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = "tests.test_project.urls"
|
ROOT_URLCONF = "test_project.urls"
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
|
|
@ -68,7 +68,7 @@ TEMPLATES = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
WSGI_APPLICATION = "tests.test_project.wsgi.application"
|
WSGI_APPLICATION = "test_project.wsgi.application"
|
||||||
|
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
from .local import *
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
"""
|
||||||
|
Django settings for test_project project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 3.0.10.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = "=yddl-40388w3e2hl$e8)revce=n67_idi8pfejtn3!+2%!_qt"
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
"admin_confirm",
|
||||||
|
"django.contrib.admin",
|
||||||
|
"django.contrib.auth",
|
||||||
|
"django.contrib.contenttypes",
|
||||||
|
"django.contrib.sessions",
|
||||||
|
"django.contrib.messages",
|
||||||
|
"django.contrib.staticfiles",
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
"django.middleware.security.SecurityMiddleware",
|
||||||
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
|
"django.middleware.common.CommonMiddleware",
|
||||||
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
|
]
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
|
"DIRS": [],
|
||||||
|
"APP_DIRS": True,
|
||||||
|
"OPTIONS": {
|
||||||
|
"context_processors": [
|
||||||
|
"django.template.context_processors.debug",
|
||||||
|
"django.template.context_processors.request",
|
||||||
|
"django.contrib.auth.context_processors.auth",
|
||||||
|
"django.contrib.messages.context_processors.messages",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"ENGINE": "django.db.backends.sqlite3",
|
||||||
|
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = "en-us"
|
||||||
|
|
||||||
|
TIME_ZONE = "UTC"
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/3.0/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = "/static/"
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
from .base import *
|
||||||
|
|
||||||
|
INSTALLED_APPS = INSTALLED_APPS + ['market']
|
||||||
|
WSGI_APPLICATION = "test_project.wsgi.application"
|
||||||
|
ROOT_URLCONF = "test_project.urls"
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
from .base import *
|
||||||
|
|
||||||
|
INSTALLED_APPS = INSTALLED_APPS + ['tests.market']
|
||||||
|
WSGI_APPLICATION = "tests.test_project.wsgi.application"
|
||||||
|
ROOT_URLCONF = "tests.test_project.urls"
|
||||||
Loading…
Reference in New Issue