diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..f29ad5b --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +django-admin-confirm-3.8 diff --git a/Makefile b/Makefile index 9aa3455..8136d45 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,6 @@ test: coverage run --branch -m pytest coverage html coverage-badge -f -o coverage.svg - python -m readme_renderer README.md -o /tmp/README.html check-readme: python -m readme_renderer README.md -o /tmp/README.html diff --git a/README.md b/README.md index 8b141ce..c51059d 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ AdminConfirmMixin is a mixin for ModelAdmin to add confirmations to change, add ![Screenshot of Change Confirmation Page](https://raw.githubusercontent.com/TrangPham/django-admin-confirm/32192d3988a9bd44c734a66baff91f02dd28136b/screenshot.png) +![Screenshot of Add Confirmation Page](https://raw.githubusercontent.com/TrangPham/django-admin-confirm/32192d3988a9bd44c734a66baff91f02dd28136b/screenshot_confirm_add.png) + ![Screenshot of Action Confirmation Page](https://raw.githubusercontent.com/TrangPham/django-admin-confirm/264900a21658cc979dd2026038db73f8a1b73c64/screenshot_confirm_action.png) 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 - 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 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. diff --git a/admin_confirm/admin.py b/admin_confirm/admin.py index 83f0bef..f5f0e61 100644 --- a/admin_confirm/admin.py +++ b/admin_confirm/admin.py @@ -134,14 +134,16 @@ class AdminConfirmMixin: changed_data = {} if form_validated: if add: - for name in form.changed_data: + for name in form.cleaned_data: new_value = getattr(new_object, name) # Don't consider default values as changed for adding + default_value = model._meta.get_field(name).get_default() if ( 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: # 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(): diff --git a/admin_confirm/templates/admin/change_data.html b/admin_confirm/templates/admin/change_data.html index 713f835..efd4b73 100644 --- a/admin_confirm/templates/admin/change_data.html +++ b/admin_confirm/templates/admin/change_data.html @@ -1,11 +1,19 @@ {% if changed_data %} -
-

Confirm Values:

- - - {% for field, values in changed_data.items %} - - {% endfor %} -
FieldCurrent ValueNew Value
{{ field }}{{ values.0 }}{{ values.1 }}
-
+
+

Confirm Values:

+ + + + + + + {% for field, values in changed_data.items %} + + + + + + {% endfor %} +
Field{% if add %} Default {% else %} Current {% endif %}ValueNew Value
{{ field }}{{ values.0 }}{{ values.1 }}
+
{% endif %} diff --git a/coverage.svg b/coverage.svg index e5db27c..5cc1bb5 100644 --- a/coverage.svg +++ b/coverage.svg @@ -9,13 +9,13 @@ - + coverage coverage - 100% - 100% + 42% + 42% diff --git a/pytest.ini b/pytest.ini index 228da49..729510f 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,4 @@ [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 -testpaths = admin_confirm \ No newline at end of file +testpaths = admin_confirm diff --git a/requirements.txt b/requirements.txt index 9fa7e6a..48ea57d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,10 @@ Django>=1.7.0 -factory-boy~=3.0.1 \ No newline at end of file +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 diff --git a/screenshot_confirm_add.png b/screenshot_confirm_add.png new file mode 100644 index 0000000..4373e12 Binary files /dev/null and b/screenshot_confirm_add.png differ diff --git a/setup.py b/setup.py index 9c95ef2..300be52 100644 --- a/setup.py +++ b/setup.py @@ -25,5 +25,4 @@ setup( # ISSUE-4: Ensure that package includes template and css folders # list files in MANIFEST.in include_package_data=True, - ) diff --git a/tests/market/migrations/0004_inventory_notes.py b/tests/market/migrations/0004_inventory_notes.py new file mode 100644 index 0000000..ab483c2 --- /dev/null +++ b/tests/market/migrations/0004_inventory_notes.py @@ -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), + ), + ] diff --git a/tests/market/models.py b/tests/market/models.py index 8b8a0bd..3ba1436 100644 --- a/tests/market/models.py +++ b/tests/market/models.py @@ -32,3 +32,4 @@ class Inventory(models.Model): ) item = models.ForeignKey(to=Item, on_delete=models.CASCADE) quantity = models.PositiveIntegerField(default=0, null=True, blank=True) + notes = models.TextField(default="This is the default", null=True, blank=True) diff --git a/tests/test_project/settings.py b/tests/test_project/settings.py index 7ce07ab..ed390d3 100644 --- a/tests/test_project/settings.py +++ b/tests/test_project/settings.py @@ -37,7 +37,7 @@ INSTALLED_APPS = [ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", - "tests.market", + "market", ] MIDDLEWARE = [ @@ -50,7 +50,7 @@ MIDDLEWARE = [ "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = "tests.test_project.urls" +ROOT_URLCONF = "test_project.urls" TEMPLATES = [ { @@ -68,7 +68,7 @@ TEMPLATES = [ }, ] -WSGI_APPLICATION = "tests.test_project.wsgi.application" +WSGI_APPLICATION = "test_project.wsgi.application" # Database diff --git a/tests/test_project/settings/__init__.py b/tests/test_project/settings/__init__.py new file mode 100644 index 0000000..8f607e4 --- /dev/null +++ b/tests/test_project/settings/__init__.py @@ -0,0 +1 @@ +from .local import * diff --git a/tests/test_project/settings/base.py b/tests/test_project/settings/base.py new file mode 100644 index 0000000..4cff103 --- /dev/null +++ b/tests/test_project/settings/base.py @@ -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/" diff --git a/tests/test_project/settings/local.py b/tests/test_project/settings/local.py new file mode 100644 index 0000000..80a24fc --- /dev/null +++ b/tests/test_project/settings/local.py @@ -0,0 +1,5 @@ +from .base import * + +INSTALLED_APPS = INSTALLED_APPS + ['market'] +WSGI_APPLICATION = "test_project.wsgi.application" +ROOT_URLCONF = "test_project.urls" diff --git a/tests/test_project/settings/test.py b/tests/test_project/settings/test.py new file mode 100644 index 0000000..2e221c3 --- /dev/null +++ b/tests/test_project/settings/test.py @@ -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"