djaxei 0.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. djaxei-0.0.0/.bumpversion.cfg +13 -0
  2. djaxei-0.0.0/.env.example +1 -0
  3. djaxei-0.0.0/.envrc.example +21 -0
  4. djaxei-0.0.0/.flake8 +8 -0
  5. djaxei-0.0.0/.gitignore +19 -0
  6. djaxei-0.0.0/.isort.cfg +13 -0
  7. djaxei-0.0.0/.pre-commit-config.yaml +78 -0
  8. djaxei-0.0.0/.python-version +5 -0
  9. djaxei-0.0.0/CHANGES.md +4 -0
  10. djaxei-0.0.0/HISTORY.md +8 -0
  11. djaxei-0.0.0/LICENSE.txt +21 -0
  12. djaxei-0.0.0/MANIFEST.in +4 -0
  13. djaxei-0.0.0/Makefile +97 -0
  14. djaxei-0.0.0/PKG-INFO +5 -0
  15. djaxei-0.0.0/README.md +45 -0
  16. djaxei-0.0.0/TODO.md +3 -0
  17. djaxei-0.0.0/pyproject.toml +68 -0
  18. djaxei-0.0.0/pytest.ini +37 -0
  19. djaxei-0.0.0/setup.cfg +4 -0
  20. djaxei-0.0.0/src/djaxei/__init__.py +1 -0
  21. djaxei-0.0.0/src/djaxei/actions.py +100 -0
  22. djaxei-0.0.0/src/djaxei/admin.py +6 -0
  23. djaxei-0.0.0/src/djaxei/apps.py +8 -0
  24. djaxei-0.0.0/src/djaxei/exceptions.py +13 -0
  25. djaxei-0.0.0/src/djaxei/exp.py +175 -0
  26. djaxei-0.0.0/src/djaxei/imp.py +40 -0
  27. djaxei-0.0.0/src/djaxei/migrations/__init__.py +0 -0
  28. djaxei-0.0.0/src/djaxei/models.py +6 -0
  29. djaxei-0.0.0/src/djaxei/modems/__init__.py +0 -0
  30. djaxei-0.0.0/src/djaxei/modems/field.py +53 -0
  31. djaxei-0.0.0/src/djaxei/modems/model.py +112 -0
  32. djaxei-0.0.0/src/djaxei/providers/__init__.py +19 -0
  33. djaxei-0.0.0/src/djaxei/providers/xlsxwriter_provider.py +15 -0
  34. djaxei-0.0.0/src/djaxei/providers/xlwt_provider.py +19 -0
  35. djaxei-0.0.0/src/djaxei/templates/djaxei/replace_with_xls.html +6 -0
  36. djaxei-0.0.0/src/djaxei/tests.py +6 -0
  37. djaxei-0.0.0/src/djaxei/views.py +6 -0
  38. djaxei-0.0.0/src/djaxei.egg-info/PKG-INFO +5 -0
  39. djaxei-0.0.0/src/djaxei.egg-info/SOURCES.txt +68 -0
  40. djaxei-0.0.0/src/djaxei.egg-info/dependency_links.txt +1 -0
  41. djaxei-0.0.0/src/djaxei.egg-info/top_level.txt +1 -0
  42. djaxei-0.0.0/tests/.coveragerc +37 -0
  43. djaxei-0.0.0/tests/conftest.py +137 -0
  44. djaxei-0.0.0/tests/demo/demoproject/__init__.py +0 -0
  45. djaxei-0.0.0/tests/demo/demoproject/app1/__init__.py +0 -0
  46. djaxei-0.0.0/tests/demo/demoproject/app1/admin.py +6 -0
  47. djaxei-0.0.0/tests/demo/demoproject/app1/apps.py +8 -0
  48. djaxei-0.0.0/tests/demo/demoproject/app1/migrations/0001_initial.py +71 -0
  49. djaxei-0.0.0/tests/demo/demoproject/app1/migrations/__init__.py +0 -0
  50. djaxei-0.0.0/tests/demo/demoproject/app1/models.py +58 -0
  51. djaxei-0.0.0/tests/demo/demoproject/app1/views.py +6 -0
  52. djaxei-0.0.0/tests/demo/demoproject/app2/__init__.py +0 -0
  53. djaxei-0.0.0/tests/demo/demoproject/app2/admin.py +6 -0
  54. djaxei-0.0.0/tests/demo/demoproject/app2/apps.py +8 -0
  55. djaxei-0.0.0/tests/demo/demoproject/app2/migrations/__init__.py +0 -0
  56. djaxei-0.0.0/tests/demo/demoproject/app2/models.py +6 -0
  57. djaxei-0.0.0/tests/demo/demoproject/app2/views.py +6 -0
  58. djaxei-0.0.0/tests/demo/demoproject/settings.py +122 -0
  59. djaxei-0.0.0/tests/demo/demoproject/urls.py +21 -0
  60. djaxei-0.0.0/tests/demo/manage.py +22 -0
  61. djaxei-0.0.0/tests/example.xlsx +0 -0
  62. djaxei-0.0.0/tests/exports/test_export.py +121 -0
  63. djaxei-0.0.0/tests/exports/test_field_list_model_modem.py +83 -0
  64. djaxei-0.0.0/tests/exports/test_roots.py +44 -0
  65. djaxei-0.0.0/tests/files/example_imp.xlsx +0 -0
  66. djaxei-0.0.0/tests/imports/exported.xlsx +0 -0
  67. djaxei-0.0.0/tests/imports/test_imp.py +179 -0
  68. djaxei-0.0.0/tests/modems/test_datetime_modems.py +41 -0
  69. djaxei-0.0.0/tests/modems/test_json_modems.py +33 -0
  70. djaxei-0.0.0/tox.ini +46 -0
@@ -0,0 +1,13 @@
1
+ [bumpversion]
2
+ current_version = 1.2.1
3
+ commit = True
4
+ tag = False
5
+ tag_name = "{new_version}"
6
+
7
+ [bumpversion:file:pyproject.toml]
8
+ search = version = "{current_version}"
9
+ replace = version = "{new_version}"
10
+
11
+ [bumpversion:file:src/djaxei/__init__.py]
12
+ search = __version__ = "{current_version}"
13
+ replace = __version__ = "{new_version}"
@@ -0,0 +1 @@
1
+ PYPI_TOKEN=...
@@ -0,0 +1,21 @@
1
+ dotenv
2
+
3
+ layout_poetry() {
4
+ if [[ ! -f pyproject.toml ]]; then
5
+ log_error 'No pyproject.toml found. Use `poetry new` or `poetry init` to create one first.'
6
+ exit 2
7
+ fi
8
+
9
+ # local VENV=$(poetry env list --full-path | cut -d' ' -f1)
10
+ local VENV='.venv'
11
+ if [[ -z $VENV || ! -d $VENV/bin ]]; then
12
+ log_error 'No created poetry virtual environment found. Use `poetry install` to create one first.'
13
+ exit 2
14
+ fi
15
+ VENV=$VENV/bin
16
+ export VIRTUAL_ENV=$(echo "$VENV" | rev | cut -d'/' -f2- | rev)
17
+ export POETRY_ACTIVE=1
18
+ PATH_add "$VENV"
19
+ }
20
+
21
+ layout poetry
djaxei-0.0.0/.flake8 ADDED
@@ -0,0 +1,8 @@
1
+ [flake8]
2
+ max-complexity = 12
3
+ max-line-length = 120
4
+ exclude = migrations settings
5
+ ignore = E401,W391,E128,E261,E731,Q000,W504,W606
6
+
7
+ per-file-ignores =
8
+ */__init__.py:F401,F403
@@ -0,0 +1,19 @@
1
+ .*
2
+ ~*
3
+ !.gitignore
4
+ !.env.example
5
+ !.envrc.example
6
+ !.bumpversion.cfg
7
+ !.flake8
8
+ !.isort.cfg
9
+ !.pre-commit-config.yaml
10
+ !tests/.coveragerc
11
+ !.python-version
12
+
13
+ __pycache__
14
+ dist
15
+
16
+ poetry.lock
17
+ db.sqlite3
18
+ *.egg-info
19
+ *.pyc
@@ -0,0 +1,13 @@
1
+ [settings]
2
+ combine_as_imports = true
3
+ default_section = THIRDPARTY
4
+ include_trailing_comma = true
5
+ ;forced_separate = django.contrib,django.utils
6
+ line_length = 80
7
+ known_future_library = future,pies
8
+ ;known_standard_library =
9
+ known_third_party = rest_framework,django,constance,rest_framework
10
+ known_first_party = bitcaster
11
+ multi_line_output = 0
12
+ balanced_wrapping = true
13
+ sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
@@ -0,0 +1,78 @@
1
+ exclude: '^$'
2
+ fail_fast: false
3
+ repos:
4
+ - repo: local
5
+ hooks:
6
+ - id: ci-cache-key
7
+ name: update ci-cache-key
8
+ entry: sh .hooks/pre-commit.sh
9
+ language: system
10
+ stages: [commit]
11
+ files: Poetry.lock
12
+
13
+ - id: isort
14
+ args:
15
+ - --check-only
16
+ exclude: tweepy
17
+ name: isort
18
+ entry: isort
19
+ language: system
20
+ types: [python]
21
+ stages: [commit]
22
+
23
+ - id: flake8
24
+ exclude: /(_plugin_template|python_twitter|migrations|tweepy)/
25
+ name: flake8
26
+ entry: flake8
27
+ language: system
28
+ types: [python]
29
+ stages: [commit]
30
+
31
+ - repo: https://github.com/Yelp/detect-secrets
32
+ rev: 0.9.1
33
+ hooks:
34
+ - id: detect-secrets
35
+ args: ['--baseline', '.secrets.baseline']
36
+ exclude: (tests/.*|.*/tenant\.sql|Pipfile\.lock|.*\.js|.gitlab-ci.yml|poetry.lock)
37
+ stages: [push]
38
+
39
+ - repo: https://github.com/pre-commit/pre-commit-hooks
40
+ rev: v2.1.0
41
+ hooks:
42
+ - id: double-quote-string-fixer
43
+ stages: [commit]
44
+
45
+ - id: debug-statements
46
+ exclude: (_plugin_template|python_twitter)
47
+ stages: [commit]
48
+
49
+ - id: end-of-file-fixer
50
+ exclude: .bumpversion.cfg
51
+ stages: [commit]
52
+
53
+ - id: check-merge-conflict
54
+ stages: [commit]
55
+
56
+ - id: check-case-conflict
57
+ stages: [commit]
58
+
59
+ - repo: https://github.com/saxix/pch
60
+ rev: fc387f4
61
+ hooks:
62
+ - id: check-version-release-match
63
+ args:
64
+ - --pythonpath=src
65
+ - --package=djaxei
66
+ stages: [push]
67
+
68
+ - id: check-untracked
69
+ args:
70
+ - src
71
+ - tests
72
+ stages: [push]
73
+
74
+ - id: check-forbidden
75
+ args:
76
+ - -p
77
+ - \.showbrowser\(
78
+ stages: [commit]
@@ -0,0 +1,5 @@
1
+ 3.9
2
+ 3.8
3
+ 3.10
4
+ 3.11
5
+ 3.12
@@ -0,0 +1,4 @@
1
+ Release 1.2.0
2
+ =============
3
+ * First changelog release
4
+ * Fixing issue with package version showing as 0.0.0
@@ -0,0 +1,8 @@
1
+ =======
2
+ History
3
+ =======
4
+
5
+ 0.1.0 (2020-02-18)
6
+ ------------------
7
+
8
+ * First release
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020, Giovanni Bronzini
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include LICENSE.txt
2
+ include HISTORY.md
3
+ include Makefile
4
+ include pyproject.toml
djaxei-0.0.0/Makefile ADDED
@@ -0,0 +1,97 @@
1
+ .PHONY: clean clean-test clean-pyc clean-build docs help
2
+ .DEFAULT_GOAL := help
3
+
4
+ VCS_CERT?=/usr/local/share/ca-certificates/path/my_company.crt
5
+
6
+ define BROWSER_PYSCRIPT
7
+ import os, webbrowser, sys
8
+
9
+ from urllib.request import pathname2url
10
+
11
+ webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
12
+ endef
13
+ export BROWSER_PYSCRIPT
14
+
15
+ define PRINT_HELP_PYSCRIPT
16
+ import re, sys
17
+
18
+ for line in sys.stdin:
19
+ match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line)
20
+ if match:
21
+ target, help = match.groups()
22
+ print("%-20s %s" % (target, help))
23
+ endef
24
+ export PRINT_HELP_PYSCRIPT
25
+
26
+ BROWSER := python -c "$$BROWSER_PYSCRIPT"
27
+
28
+ help:
29
+ @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
30
+
31
+ clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
32
+
33
+ clean-build: ## remove build artifacts
34
+ rm -fr pip-wheel-metadata/
35
+ rm -fr build/
36
+ rm -fr dist/
37
+ rm -fr .eggs/
38
+ find . -name '*.egg-info' -exec rm -fr {} +
39
+ find . -name '*.egg' -exec rm -f {} +
40
+
41
+ clean-pyc: ## remove Python file artifacts
42
+ find . -name '*.pyc' -exec rm -f {} +
43
+ find . -name '*.pyo' -exec rm -f {} +
44
+ find . -name '*~' -exec rm -f {} +
45
+ find . -name '__pycache__' -exec rm -fr {} +
46
+
47
+ clean-test: ## remove test and coverage artifacts
48
+ rm -fr .tox/
49
+ rm -f .coverage
50
+ rm -fr htmlcov/
51
+ rm -fr .pytest_cache
52
+
53
+ lint: ## check style with flake8
54
+ flake8 wlsclick tests
55
+
56
+ test: ## run tests quickly with the default Python
57
+ pytest
58
+
59
+ test-all: ## run tests on every Python version with tox
60
+ tox
61
+
62
+ coverage: ## check code coverage quickly with the default Python
63
+ coverage run --source wlsclick -m pytest
64
+ coverage report -m
65
+ coverage html
66
+ $(BROWSER) htmlcov/index.html
67
+
68
+ docs: ## generate Sphinx HTML documentation, including API docs
69
+ rm -f docs/wlsclick.rst
70
+ rm -f docs/modules.rst
71
+ sphinx-apidoc -o docs/ wlsclick
72
+ $(MAKE) -C docs clean
73
+ $(MAKE) -C docs html
74
+ $(BROWSER) docs/_build/html/index.html
75
+
76
+ servedocs: docs ## compile the docs watching for changes
77
+ watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
78
+
79
+ release: dist ## package and upload a release
80
+ poetry config pypi-token.pypi ${PYPI_TOKEN}
81
+ poetry publish
82
+
83
+ dist: clean ## builds source and wheel package
84
+ poetry build -f sdist
85
+
86
+ install: clean ## install the package to the active Python's site-packages
87
+ poetry install
88
+
89
+ bump: ## Bumps version
90
+ @while :; do \
91
+ read -r -p "bumpversion [major/minor/patch]: " PART; \
92
+ case "$$PART" in \
93
+ major|minor|patch) break ;; \
94
+ esac \
95
+ done ; \
96
+ bumpversion --no-commit --allow-dirty $$PART
97
+ @grep "^version = " pyproject.toml
djaxei-0.0.0/PKG-INFO ADDED
@@ -0,0 +1,5 @@
1
+ Metadata-Version: 2.4
2
+ Name: djaxei
3
+ Version: 0.0.0
4
+ License-File: LICENSE.txt
5
+ Dynamic: license-file
djaxei-0.0.0/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # A django admin extension for importing exporting records from/to xls/ods
2
+
3
+ A Python library project using:
4
+ * pytest
5
+ * flake8
6
+ * tox
7
+ * bumpversion
8
+ * isort
9
+
10
+ * Free software: MIT license
11
+ * Documentation: __TBD__
12
+
13
+
14
+ # Features
15
+
16
+ - Requires Python >=3.8, Django>=3.2
17
+ - Currently work only with xlsxwriter
18
+
19
+ - Could help if use [direnv](https://direnv.net/) in dev environment
20
+
21
+ # Contributing
22
+
23
+ See [demo](tests%2Fdemo) in tests folder
24
+
25
+ * TODO
26
+
27
+ # Dev setup
28
+
29
+ 1. install direnv
30
+ 2. install pyenv
31
+ 3. clone project: `git clone https://github.com/GigiusB/djaxei.git`
32
+ 4. `cd djaxei`
33
+ 5. ```pyenv install `cat .python-version` ```
34
+ 6. `pip install -U poetry` # this should install poetry in your pyenv python
35
+ 7. `cp .env.example .env`
36
+ 8. `cp .envrc.example .envrc`
37
+ 9. `direnv allow`
38
+ 10. ```poetry env use `pyenv which python` ```
39
+ 11. `cd .. ; cd -` # see if it loads the env
40
+ 12. poetry install
41
+ 13. pytest
42
+
43
+ Credits
44
+ -------
45
+
djaxei-0.0.0/TODO.md ADDED
@@ -0,0 +1,3 @@
1
+ # TODO
2
+
3
+ 1. Add i18n support
@@ -0,0 +1,68 @@
1
+ [tool.poetry]
2
+ name = "djaxei"
3
+ version = "1.2.1"
4
+ description = "A django admin extension for importing exporting records from/to xls/ods"
5
+ authors = ["Giovanni Bronzini <g.bronzini@gmail.com>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ repository = "https://github.com/GigiusB/djaxei.git"
9
+ keywords = ["xls",]
10
+ include = ["README.md", "HISTORY.md", "Makefile"]
11
+ packages = [
12
+ { include = "djaxei", from = "src" },
13
+ ]
14
+
15
+ [tool.poetry.dependencies]
16
+ python = ">=3.8.7,<4"
17
+ django = ">=3.2,<5"
18
+ #openpyxl = { version = "<4", optional = true }
19
+ #xlwt = {version = ">=1.2.0", optional = true}
20
+ #xlsxwriter = {version = ">=1.2.8", optional = true}
21
+ openpyxl = ">=3.0.0"
22
+
23
+ #[tool.poetry.dev-dependencies]
24
+ #pytest = "^6.2.5"
25
+ #tox = "^3.24.4"
26
+ #pytest-django = "^4.5.2"
27
+ #factory-boy = "^3.2.1"
28
+ #pytest-pythonpath = "^0.7.3"
29
+ #flake8 = "^4.0.1"
30
+ #isort = "^5.10.1"
31
+ #django-webtest = "^1.9.8"
32
+ #pytest-env = "^0.6.2"
33
+ #pytest-coverage = "^0.0"
34
+ #pytest-echo = "^1.7.1"
35
+
36
+ #[tool.poetry.extras]
37
+ #openpyxl = ["openpyxl"]
38
+ #xlsxwriter = ["xlsxwriter"]
39
+ #xlwt = ["xlwt"]
40
+
41
+ #requires = ["poetry>=1.1"]
42
+ #build-backend = "poetry.masonry.api"
43
+
44
+ #[tool.poetry.group.dev.dependencies]
45
+ #openpyxl = "^3.1.0"
46
+ #xlsxwriter = "^3.0.7"
47
+ pytz = "^2024.1"
48
+
49
+ [tool.poetry.group.dev.dependencies]
50
+ pytest = "*"
51
+ pytest-django = "*"
52
+ flake8 = "*"
53
+ isort = "*"
54
+ bumpversion = "*"
55
+ factory-boy = "*"
56
+ pytest-env = "*"
57
+ pytest-coverage = "*"
58
+ pytest-echo = "*"
59
+ tox = "*"
60
+
61
+
62
+ [build-system]
63
+ requires = [
64
+ "setuptools>=61",
65
+ "setuptools_scm[toml]>=6.2"
66
+ ]
67
+
68
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,37 @@
1
+ [pytest]
2
+ env =
3
+ DJANGO_SETTINGS_MODULE=demoproject.settings
4
+ norecursedirs = data _plugin_template ~* .* node_modules
5
+ pythonpath = ./src, ./tests/demo
6
+ django_find_project = false
7
+ ;log_format = %(asctime)s %(levelname)s %(message)s
8
+ ;log_date_format = %Y-%m-%d %H:%M:%S
9
+ ;log_print = true
10
+ log_cli = 0
11
+ log_cli_level = INFO
12
+ log_cli_format = [%(levelname)-8s] %(message)s (%(filename)s:%(lineno)s)
13
+ log_cli_date_format=%Y-%m-%d %H:%M:%S
14
+ addopts =
15
+ -rs
16
+ -p no:xdist
17
+ -p no:pep8
18
+ -p no:warnings
19
+ --reuse-db
20
+ --tb=short
21
+ --capture=no
22
+ --cov-report=html
23
+ --cov-config=tests/.coveragerc
24
+ --cov=djaxei
25
+ --echo-version=django
26
+
27
+ markers =
28
+ plugin: dispatcher test
29
+ incremental: incremental tests
30
+ skipif_missing: skip test if environment variable does not exists
31
+ paid: paid plugin test
32
+ cli: CLI related tests
33
+ selenium: Run selenium functional tests
34
+
35
+ python_files=test_*.py
36
+ filterwarnings =
37
+ ignore::DeprecationWarning
djaxei-0.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "1.2.1"
@@ -0,0 +1,100 @@
1
+ from django.contrib import messages
2
+ from django.contrib.admin import helpers
3
+ from django.contrib.admin.utils import get_deleted_objects, model_ngettext
4
+ from django.core.exceptions import PermissionDenied
5
+ from django.db import router
6
+ from django.template.response import TemplateResponse
7
+ from django.utils.encoding import force_text
8
+ from django.utils.translation import ugettext as _, ugettext_lazy
9
+
10
+
11
+ def replace_selected_validator(modeladmin, request, queryset):
12
+ # Check that the user has delete permission for the actual model
13
+ if not modeladmin.has_delete_permission(request):
14
+ raise PermissionDenied
15
+ return None
16
+
17
+
18
+ def replace_selected_factory(breadcrumb=None, validate_queryset=None):
19
+ def replace_selected(modeladmin, request, queryset):
20
+ """
21
+ Default action which deletes the selected objects.
22
+
23
+ This action first displays a confirmation page which shows all the
24
+ deletable objects, or, if the user has no permission one of the related
25
+ childs (foreignkeys), a "permission denied" message.
26
+
27
+ Next, it deletes all selected objects and redirects back to the change list.
28
+ """
29
+ opts = modeladmin.model._meta
30
+ app_label = opts.app_label
31
+
32
+ if not modeladmin.has_delete_permission(request):
33
+ raise PermissionDenied
34
+
35
+ if validate_queryset:
36
+ validation_error_message = validate_queryset(modeladmin, request, queryset)
37
+ if validation_error_message:
38
+ modeladmin.message_user(request, validation_error_message, messages.WARNING)
39
+ return None
40
+
41
+ using = router.db_for_write(modeladmin.model)
42
+
43
+ # Populate deletable_objects, a data structure of all related objects that
44
+ # will also be deleted.
45
+ deletable_objects, model_count, perms_needed, protected = get_deleted_objects(
46
+ queryset, opts, request.user, modeladmin.admin_site, using)
47
+
48
+ # The user has already confirmed the deletion.
49
+ # Do the deletion and return a None to display the change list view again.
50
+ if request.POST.get('post') and not protected:
51
+ if perms_needed:
52
+ raise PermissionDenied
53
+ n = queryset.count()
54
+ if n:
55
+ for obj in queryset:
56
+ obj_display = force_text(obj)
57
+ modeladmin.log_deletion(request, obj, obj_display)
58
+ queryset.delete()
59
+ modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % {
60
+ "count": n, "items": model_ngettext(modeladmin.opts, n)
61
+ }, messages.SUCCESS)
62
+ # Return None to display the change list page again.
63
+ return None
64
+
65
+ if len(queryset) == 1:
66
+ objects_name = force_text(opts.verbose_name)
67
+ else:
68
+ objects_name = force_text(opts.verbose_name_plural)
69
+
70
+ if perms_needed or protected:
71
+ title = _("Cannot delete %(name)s") % {"name": objects_name}
72
+ else:
73
+ title = _("Are you sure you want to replace those records with the content of the spreadsheet?")
74
+
75
+ context = dict(
76
+ modeladmin.admin_site.each_context(request),
77
+ title=title,
78
+ objects_name=objects_name,
79
+ deletable_objects=[deletable_objects],
80
+ model_count=dict(model_count).items(),
81
+ queryset=queryset,
82
+ perms_lacking=perms_needed,
83
+ protected=protected,
84
+ opts=opts,
85
+ action_checkbox_name=helpers.ACTION_CHECKBOX_NAME,
86
+ media=modeladmin.media,
87
+ )
88
+
89
+ request.current_app = modeladmin.admin_site.name
90
+
91
+ # Display the confirmation page
92
+ return TemplateResponse(request, modeladmin.delete_selected_confirmation_template or [
93
+ "admin/%s/%s/delete_selected_confirmation.html" % (app_label, opts.model_name),
94
+ "admin/%s/delete_selected_confirmation.html" % app_label,
95
+ "admin/delete_selected_confirmation.html"
96
+ ], context)
97
+
98
+ replace_selected.short_description = \
99
+ breadcrumb or ugettext_lazy("Replace %(verbose_name_plural)s with xls")
100
+ return replace_selected
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ from __future__ import unicode_literals
3
+
4
+ from django.contrib import admin
5
+
6
+ # Register your models here.
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+ from __future__ import unicode_literals
3
+
4
+ from django.apps import AppConfig
5
+
6
+
7
+ class DjaxeiConfig(AppConfig):
8
+ name = 'djaxei'
@@ -0,0 +1,13 @@
1
+ class ImportException(Exception):
2
+ def __init__(self, cause, worksheet=None, *args):
3
+ super(ImportException, self).__init__(*args)
4
+ self.worksheet = worksheet
5
+ self.cause = cause
6
+
7
+ def __str__(self):
8
+ if hasattr(self.cause, 'reference'):
9
+ msg = "[%s:%s] %s: %s" % (self.worksheet, self.cause.reference, self.cause.__class__.__name__, str(self.cause))
10
+ else:
11
+ msg = "[%s] %s: %s" % (self.worksheet, self.cause.__class__.__name__, str(self.cause))
12
+ return msg
13
+