django-modelsheet 0.3.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 (168) hide show
  1. django_modelsheet-0.3.0/.github/workflows/ci.yml +92 -0
  2. django_modelsheet-0.3.0/.github/workflows/docs-checks.yml +31 -0
  3. django_modelsheet-0.3.0/.github/workflows/docs.yml +31 -0
  4. django_modelsheet-0.3.0/.github/workflows/workflow.yml +58 -0
  5. django_modelsheet-0.3.0/CHANGELOG.md +39 -0
  6. django_modelsheet-0.3.0/CONTRIBUTING.md +18 -0
  7. django_modelsheet-0.3.0/LICENSE +21 -0
  8. django_modelsheet-0.3.0/MANIFEST.in +14 -0
  9. django_modelsheet-0.3.0/PKG-INFO +210 -0
  10. django_modelsheet-0.3.0/README.md +177 -0
  11. django_modelsheet-0.3.0/SECURITY.md +16 -0
  12. django_modelsheet-0.3.0/demo/__init__.py +0 -0
  13. django_modelsheet-0.3.0/demo/settings.py +76 -0
  14. django_modelsheet-0.3.0/demo/shop/__init__.py +0 -0
  15. django_modelsheet-0.3.0/demo/shop/admin.py +46 -0
  16. django_modelsheet-0.3.0/demo/shop/apps.py +6 -0
  17. django_modelsheet-0.3.0/demo/shop/management/__init__.py +0 -0
  18. django_modelsheet-0.3.0/demo/shop/management/commands/__init__.py +0 -0
  19. django_modelsheet-0.3.0/demo/shop/management/commands/seed_demo.py +38 -0
  20. django_modelsheet-0.3.0/demo/shop/migrations/0001_initial.py +75 -0
  21. django_modelsheet-0.3.0/demo/shop/migrations/__init__.py +0 -0
  22. django_modelsheet-0.3.0/demo/shop/models.py +39 -0
  23. django_modelsheet-0.3.0/demo/urls.py +4 -0
  24. django_modelsheet-0.3.0/django_modelsheet.egg-info/PKG-INFO +210 -0
  25. django_modelsheet-0.3.0/django_modelsheet.egg-info/SOURCES.txt +166 -0
  26. django_modelsheet-0.3.0/django_modelsheet.egg-info/dependency_links.txt +1 -0
  27. django_modelsheet-0.3.0/django_modelsheet.egg-info/requires.txt +16 -0
  28. django_modelsheet-0.3.0/django_modelsheet.egg-info/top_level.txt +1 -0
  29. django_modelsheet-0.3.0/docs/api.be.md +65 -0
  30. django_modelsheet-0.3.0/docs/api.md +52 -0
  31. django_modelsheet-0.3.0/docs/api.zh.md +65 -0
  32. django_modelsheet-0.3.0/docs/background.be.md +53 -0
  33. django_modelsheet-0.3.0/docs/background.md +54 -0
  34. django_modelsheet-0.3.0/docs/background.zh.md +53 -0
  35. django_modelsheet-0.3.0/docs/benchmark-100k.json +36 -0
  36. django_modelsheet-0.3.0/docs/benchmark-1m.json +36 -0
  37. django_modelsheet-0.3.0/docs/benchmark-bulk.json +46 -0
  38. django_modelsheet-0.3.0/docs/benchmarks.be.md +22 -0
  39. django_modelsheet-0.3.0/docs/benchmarks.md +26 -0
  40. django_modelsheet-0.3.0/docs/benchmarks.zh.md +20 -0
  41. django_modelsheet-0.3.0/docs/extensions.be.md +60 -0
  42. django_modelsheet-0.3.0/docs/extensions.md +52 -0
  43. django_modelsheet-0.3.0/docs/extensions.zh.md +60 -0
  44. django_modelsheet-0.3.0/docs/formulas.be.md +37 -0
  45. django_modelsheet-0.3.0/docs/formulas.md +46 -0
  46. django_modelsheet-0.3.0/docs/formulas.zh.md +37 -0
  47. django_modelsheet-0.3.0/docs/guide/bulk.be.md +60 -0
  48. django_modelsheet-0.3.0/docs/guide/bulk.md +60 -0
  49. django_modelsheet-0.3.0/docs/guide/bulk.zh.md +58 -0
  50. django_modelsheet-0.3.0/docs/guide/configuration.be.md +66 -0
  51. django_modelsheet-0.3.0/docs/guide/configuration.md +66 -0
  52. django_modelsheet-0.3.0/docs/guide/configuration.zh.md +66 -0
  53. django_modelsheet-0.3.0/docs/guide/demo.be.md +43 -0
  54. django_modelsheet-0.3.0/docs/guide/demo.md +43 -0
  55. django_modelsheet-0.3.0/docs/guide/demo.zh.md +43 -0
  56. django_modelsheet-0.3.0/docs/guide/documentation.be.md +32 -0
  57. django_modelsheet-0.3.0/docs/guide/documentation.md +32 -0
  58. django_modelsheet-0.3.0/docs/guide/documentation.zh.md +32 -0
  59. django_modelsheet-0.3.0/docs/guide/editing.be.md +45 -0
  60. django_modelsheet-0.3.0/docs/guide/editing.md +45 -0
  61. django_modelsheet-0.3.0/docs/guide/editing.zh.md +45 -0
  62. django_modelsheet-0.3.0/docs/guide/formulas.be.md +69 -0
  63. django_modelsheet-0.3.0/docs/guide/formulas.md +69 -0
  64. django_modelsheet-0.3.0/docs/guide/formulas.zh.md +69 -0
  65. django_modelsheet-0.3.0/docs/guide/permissions.be.md +62 -0
  66. django_modelsheet-0.3.0/docs/guide/permissions.md +62 -0
  67. django_modelsheet-0.3.0/docs/guide/permissions.zh.md +62 -0
  68. django_modelsheet-0.3.0/docs/guide/quickstart.be.md +78 -0
  69. django_modelsheet-0.3.0/docs/guide/quickstart.md +78 -0
  70. django_modelsheet-0.3.0/docs/guide/quickstart.zh.md +78 -0
  71. django_modelsheet-0.3.0/docs/guide/releases.be.md +70 -0
  72. django_modelsheet-0.3.0/docs/guide/releases.md +70 -0
  73. django_modelsheet-0.3.0/docs/guide/releases.zh.md +70 -0
  74. django_modelsheet-0.3.0/docs/guide/troubleshooting.be.md +41 -0
  75. django_modelsheet-0.3.0/docs/guide/troubleshooting.md +41 -0
  76. django_modelsheet-0.3.0/docs/guide/troubleshooting.zh.md +41 -0
  77. django_modelsheet-0.3.0/docs/index.be.md +110 -0
  78. django_modelsheet-0.3.0/docs/index.md +110 -0
  79. django_modelsheet-0.3.0/docs/index.zh.md +110 -0
  80. django_modelsheet-0.3.0/docs/playground.be.md +37 -0
  81. django_modelsheet-0.3.0/docs/playground.md +37 -0
  82. django_modelsheet-0.3.0/docs/playground.zh.md +37 -0
  83. django_modelsheet-0.3.0/docs/releasing.be.md +51 -0
  84. django_modelsheet-0.3.0/docs/releasing.md +64 -0
  85. django_modelsheet-0.3.0/docs/releasing.zh.md +44 -0
  86. django_modelsheet-0.3.0/docs/validation.be.md +82 -0
  87. django_modelsheet-0.3.0/docs/validation.md +114 -0
  88. django_modelsheet-0.3.0/docs/validation.zh.md +78 -0
  89. django_modelsheet-0.3.0/frontend/demo-e2e/playground.spec.ts +71 -0
  90. django_modelsheet-0.3.0/frontend/e2e/sheet.spec.ts +355 -0
  91. django_modelsheet-0.3.0/frontend/package-lock.json +1707 -0
  92. django_modelsheet-0.3.0/frontend/package.json +25 -0
  93. django_modelsheet-0.3.0/frontend/playwright.config.ts +13 -0
  94. django_modelsheet-0.3.0/frontend/playwright.demo.config.ts +10 -0
  95. django_modelsheet-0.3.0/frontend/src/buffer.ts +118 -0
  96. django_modelsheet-0.3.0/frontend/src/demo-session.ts +66 -0
  97. django_modelsheet-0.3.0/frontend/src/demo.css +9 -0
  98. django_modelsheet-0.3.0/frontend/src/demo.ts +254 -0
  99. django_modelsheet-0.3.0/frontend/src/formula.ts +260 -0
  100. django_modelsheet-0.3.0/frontend/src/grid-editors.css +28 -0
  101. django_modelsheet-0.3.0/frontend/src/grid-selection.ts +32 -0
  102. django_modelsheet-0.3.0/frontend/src/i18n.ts +24 -0
  103. django_modelsheet-0.3.0/frontend/src/main.ts +518 -0
  104. django_modelsheet-0.3.0/frontend/src/style.css +9 -0
  105. django_modelsheet-0.3.0/frontend/tests/buffer.test.ts +104 -0
  106. django_modelsheet-0.3.0/frontend/tests/demo-session.test.ts +55 -0
  107. django_modelsheet-0.3.0/frontend/tests/formula.test.ts +22 -0
  108. django_modelsheet-0.3.0/frontend/tsconfig.json +22 -0
  109. django_modelsheet-0.3.0/frontend/vite.config.ts +12 -0
  110. django_modelsheet-0.3.0/frontend/vite.demo.config.ts +19 -0
  111. django_modelsheet-0.3.0/frontend/vitest.config.ts +3 -0
  112. django_modelsheet-0.3.0/manage.py +8 -0
  113. django_modelsheet-0.3.0/modelsheet/__init__.py +1 -0
  114. django_modelsheet-0.3.0/modelsheet/adapters.py +121 -0
  115. django_modelsheet-0.3.0/modelsheet/admin.py +325 -0
  116. django_modelsheet-0.3.0/modelsheet/apps.py +14 -0
  117. django_modelsheet-0.3.0/modelsheet/background.py +44 -0
  118. django_modelsheet-0.3.0/modelsheet/bulk.py +430 -0
  119. django_modelsheet-0.3.0/modelsheet/checks.py +90 -0
  120. django_modelsheet-0.3.0/modelsheet/conf.py +42 -0
  121. django_modelsheet-0.3.0/modelsheet/errors.py +18 -0
  122. django_modelsheet-0.3.0/modelsheet/formula/__init__.py +3 -0
  123. django_modelsheet-0.3.0/modelsheet/formula/engine.py +422 -0
  124. django_modelsheet-0.3.0/modelsheet/locale/ru/LC_MESSAGES/django.mo +0 -0
  125. django_modelsheet-0.3.0/modelsheet/locale/ru/LC_MESSAGES/django.po +8 -0
  126. django_modelsheet-0.3.0/modelsheet/locale/ru/LC_MESSAGES/djangojs.mo +0 -0
  127. django_modelsheet-0.3.0/modelsheet/locale/ru/LC_MESSAGES/djangojs.po +188 -0
  128. django_modelsheet-0.3.0/modelsheet/management/__init__.py +0 -0
  129. django_modelsheet-0.3.0/modelsheet/management/commands/__init__.py +0 -0
  130. django_modelsheet-0.3.0/modelsheet/management/commands/modelsheet_cleanup.py +24 -0
  131. django_modelsheet-0.3.0/modelsheet/management/commands/modelsheet_roles.py +58 -0
  132. django_modelsheet-0.3.0/modelsheet/metadata.py +42 -0
  133. django_modelsheet-0.3.0/modelsheet/migrations/0001_initial.py +114 -0
  134. django_modelsheet-0.3.0/modelsheet/migrations/0002_operation_preview_expires_at.py +26 -0
  135. django_modelsheet-0.3.0/modelsheet/migrations/__init__.py +0 -0
  136. django_modelsheet-0.3.0/modelsheet/models.py +64 -0
  137. django_modelsheet-0.3.0/modelsheet/permissions.py +72 -0
  138. django_modelsheet-0.3.0/modelsheet/py.typed +0 -0
  139. django_modelsheet-0.3.0/modelsheet/query.py +133 -0
  140. django_modelsheet-0.3.0/modelsheet/registry.py +22 -0
  141. django_modelsheet-0.3.0/modelsheet/services.py +491 -0
  142. django_modelsheet-0.3.0/modelsheet/static/modelsheet/THIRD_PARTY_LICENSES.txt +49 -0
  143. django_modelsheet-0.3.0/modelsheet/static/modelsheet/sheet.css +1 -0
  144. django_modelsheet-0.3.0/modelsheet/static/modelsheet/sheet.js +13538 -0
  145. django_modelsheet-0.3.0/modelsheet/templates/modelsheet/audit.html +14 -0
  146. django_modelsheet-0.3.0/modelsheet/templates/modelsheet/change_list.html +6 -0
  147. django_modelsheet-0.3.0/modelsheet/templates/modelsheet/sheet.html +11 -0
  148. django_modelsheet-0.3.0/modelsheet/templates/modelsheet/unavailable.html +2 -0
  149. django_modelsheet-0.3.0/modelsheet/views.py +91 -0
  150. django_modelsheet-0.3.0/pyproject.toml +49 -0
  151. django_modelsheet-0.3.0/scripts/benchmark.py +116 -0
  152. django_modelsheet-0.3.0/scripts/benchmark_bulk.py +141 -0
  153. django_modelsheet-0.3.0/scripts/check_docs_locales.py +32 -0
  154. django_modelsheet-0.3.0/scripts/check_pypi_name.py +25 -0
  155. django_modelsheet-0.3.0/scripts/check_release.py +55 -0
  156. django_modelsheet-0.3.0/scripts/docs_assets.py +13 -0
  157. django_modelsheet-0.3.0/scripts/package_smoke.py +135 -0
  158. django_modelsheet-0.3.0/setup.cfg +4 -0
  159. django_modelsheet-0.3.0/tests/__init__.py +0 -0
  160. django_modelsheet-0.3.0/tests/conftest.py +65 -0
  161. django_modelsheet-0.3.0/tests/formula_cases.json +54 -0
  162. django_modelsheet-0.3.0/tests/test_api.py +311 -0
  163. django_modelsheet-0.3.0/tests/test_bulk.py +417 -0
  164. django_modelsheet-0.3.0/tests/test_concurrency.py +62 -0
  165. django_modelsheet-0.3.0/tests/test_configuration.py +178 -0
  166. django_modelsheet-0.3.0/tests/test_formula.py +111 -0
  167. django_modelsheet-0.3.0/tests/test_migrations.py +68 -0
  168. django_modelsheet-0.3.0/tests/test_release.py +85 -0
@@ -0,0 +1,92 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ pull_request:
5
+ workflow_call:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ python:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ include:
17
+ - {python: '3.11', django: '5.2', db: sqlite}
18
+ - {python: '3.12', django: '5.2', db: sqlite}
19
+ - {python: '3.13', django: '5.2', db: sqlite}
20
+ - {python: '3.14', django: '5.2', db: sqlite}
21
+ - {python: '3.12', django: '6.0', db: sqlite}
22
+ - {python: '3.13', django: '6.0', db: sqlite}
23
+ - {python: '3.14', django: '6.0', db: sqlite}
24
+ - {python: '3.12', django: '6.1', db: sqlite}
25
+ - {python: '3.13', django: '6.1', db: sqlite}
26
+ - {python: '3.14', django: '6.1', db: sqlite}
27
+ - {python: '3.13', django: '5.2', db: postgres}
28
+ - {python: '3.13', django: '6.0', db: postgres}
29
+ - {python: '3.13', django: '6.1', db: postgres}
30
+ - {python: '3.13', django: '5.2', db: mysql}
31
+ - {python: '3.13', django: '6.0', db: mysql}
32
+ - {python: '3.13', django: '6.1', db: mysql}
33
+ services:
34
+ postgres:
35
+ image: postgres:16
36
+ env: {POSTGRES_DB: modelsheet, POSTGRES_USER: modelsheet, POSTGRES_PASSWORD: modelsheet}
37
+ ports: ['5432:5432']
38
+ options: >-
39
+ --health-cmd "pg_isready -U modelsheet"
40
+ --health-interval 10s --health-timeout 5s --health-retries 10
41
+ mysql:
42
+ image: mysql:8.4
43
+ env: {MYSQL_DATABASE: modelsheet, MYSQL_ROOT_PASSWORD: modelsheet}
44
+ ports: ['3306:3306']
45
+ options: >-
46
+ --health-cmd "mysqladmin ping -h localhost -pmodelsheet"
47
+ --health-interval 10s --health-timeout 5s --health-retries 10
48
+ env:
49
+ MODELSHEET_DB: '${{ matrix.db }}'
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+ - uses: actions/setup-python@v5
53
+ with: {python-version: '${{ matrix.python }}'}
54
+ - run: pip install -e '.[test,postgres,mysql]' 'Django~=${{ matrix.django }}.0'
55
+ - run: python manage.py check && python manage.py makemigrations --check --dry-run
56
+ - run: python -m ruff check .
57
+ - run: python -m pytest -q
58
+
59
+ browser-and-package:
60
+ runs-on: ubuntu-latest
61
+ steps:
62
+ - uses: actions/checkout@v4
63
+ - uses: actions/setup-python@v5
64
+ with: {python-version: '3.13'}
65
+ - uses: actions/setup-node@v4
66
+ with: {node-version: '22', cache: npm, cache-dependency-path: frontend/package-lock.json}
67
+ - run: pip install -e '.[test]' twine
68
+ - run: python scripts/check_release.py --stable
69
+ - run: npm ci && npm test && npm run build
70
+ working-directory: frontend
71
+ - run: git diff --exit-code -- modelsheet/static
72
+ - run: npx playwright install --with-deps chromium && npm run test:e2e
73
+ working-directory: frontend
74
+ - run: python -m build && python -m twine check dist/*
75
+ - run: python scripts/package_smoke.py
76
+ - run: python scripts/package_smoke.py --upgrade-from 0.3.0a2
77
+ - uses: actions/upload-artifact@v4
78
+ with:
79
+ name: pypi-distributions
80
+ path: dist/
81
+ if-no-files-found: error
82
+ - uses: actions/upload-artifact@v4
83
+ if: always()
84
+ with:
85
+ name: browser-reports-and-distributions
86
+ path: |
87
+ frontend/test-results
88
+ frontend/playwright-report
89
+ dist
90
+
91
+ documentation:
92
+ uses: ./.github/workflows/docs-checks.yml
@@ -0,0 +1,31 @@
1
+ name: Documentation checks
2
+ on:
3
+ workflow_call:
4
+ permissions:
5
+ contents: read
6
+ jobs:
7
+ build:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v6
11
+ - uses: actions/setup-python@v6
12
+ with:
13
+ python-version: '3.13'
14
+ cache: pip
15
+ cache-dependency-path: requirements-docs.txt
16
+ - run: pip install -r requirements-docs.txt
17
+ - uses: actions/setup-node@v6
18
+ with:
19
+ node-version: '22'
20
+ cache: npm
21
+ cache-dependency-path: frontend/package-lock.json
22
+ - run: npm ci && npm test && npm run build:demo
23
+ working-directory: frontend
24
+ - run: git diff --exit-code -- docs/assets/playground
25
+ - run: python scripts/check_docs_locales.py
26
+ - run: mkdocs build --strict
27
+ - run: npx playwright install --with-deps chromium && npm run test:demo
28
+ working-directory: frontend
29
+ - uses: actions/upload-pages-artifact@v4
30
+ with:
31
+ path: site
@@ -0,0 +1,31 @@
1
+ name: Documentation
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ paths: ['docs/**', 'frontend/**', 'mkdocs.yml', 'requirements-docs.txt', 'scripts/check_docs_locales.py', 'scripts/docs_assets.py', '.github/workflows/docs.yml', '.github/workflows/docs-checks.yml']
6
+ pull_request:
7
+ paths: ['docs/**', 'frontend/**', 'mkdocs.yml', 'requirements-docs.txt', 'scripts/check_docs_locales.py', 'scripts/docs_assets.py', '.github/workflows/docs.yml', '.github/workflows/docs-checks.yml']
8
+ workflow_dispatch:
9
+ permissions:
10
+ contents: read
11
+ concurrency:
12
+ group: documentation-${{ github.ref }}
13
+ cancel-in-progress: true
14
+ jobs:
15
+ build:
16
+ uses: ./.github/workflows/docs-checks.yml
17
+ deploy:
18
+ if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
19
+ needs: build
20
+ runs-on: ubuntu-latest
21
+ permissions:
22
+ pages: write
23
+ id-token: write
24
+ environment:
25
+ name: github-pages
26
+ url: ${{ steps.deployment.outputs.page_url }}
27
+ steps:
28
+ - uses: actions/configure-pages@v5
29
+ - name: Deploy documentation
30
+ id: deployment
31
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,58 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ publish:
9
+ description: Upload version from pyproject.toml to PyPI (leave off to check the build)
10
+ type: boolean
11
+ required: true
12
+ default: false
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ concurrency:
18
+ group: pypi-publishing
19
+ cancel-in-progress: false
20
+
21
+ jobs:
22
+ metadata:
23
+ name: Check stable release metadata
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: actions/setup-python@v5
28
+ with: {python-version: '3.13'}
29
+ - name: Check versions and release tag
30
+ env:
31
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
32
+ run: python scripts/check_release.py --stable --tag "$RELEASE_TAG"
33
+
34
+ validate:
35
+ name: Full release validation
36
+ needs: metadata
37
+ uses: ./.github/workflows/ci.yml
38
+
39
+ publish:
40
+ name: Publish distributions to PyPI
41
+ needs: [metadata, validate]
42
+ if: >-
43
+ github.repository == 'svalench/django-modelsheet' &&
44
+ (github.event_name == 'release' ||
45
+ (inputs.publish && github.ref == 'refs/heads/main'))
46
+ runs-on: ubuntu-latest
47
+ environment:
48
+ name: pypi
49
+ url: https://pypi.org/p/django-modelsheet
50
+ permissions:
51
+ id-token: write
52
+ steps:
53
+ - uses: actions/download-artifact@v4
54
+ with:
55
+ name: pypi-distributions
56
+ path: dist/
57
+ - name: Publish using PyPI Trusted Publishing
58
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 — 2026-10-25
4
+
5
+ - Preserve edits, undo/redo and save payloads for string primary keys such as `__proto__` and `constructor`.
6
+ - Store an immutable preview deadline; cancel/resume cannot renew an expired plan or rebuild an empty plan.
7
+ - Add migration `0002` to expire legacy unconfirmed plans conservatively while preserving history and operation items. Run migrations and collectstatic during upgrade.
8
+ - Synchronize Python/npm versions and stable metadata; gate publishing on the full database/Python matrix, browser tests, strict documentation and wheel upgrade smoke checks.
9
+
10
+ - Reject bulk previews containing rows hidden by object permissions before calculating aggregates.
11
+ - Cache bulk formula parsing and query aggregates within each immutable plan, preserving formula budgets and lazy branches.
12
+ - Return existing bulk previews on idempotent retries even after their view snapshot expires or is removed.
13
+ - Lock editing and navigation while saving/loading so pending changes cannot be silently discarded.
14
+ - Invalidate bulk previews for structural edits and ignore stale preview/poll responses.
15
+ - Add permission, retry, formula-cache and browser regression tests plus an isolated bulk benchmark.
16
+ - Enable sheets through `ModelSheetAdmin` registration without a required settings list.
17
+ - Discover role models from enabled Admin registrations, including custom Admin sites.
18
+ - Keep `MODELSHEET["models"]` as an optional restriction for existing projects.
19
+
20
+ ## 0.3.0a2 — 2026-10-24
21
+
22
+ - Keep unchanged numeric cells out of the local change buffer.
23
+ - Constrain cell editors to their cells and reset inherited form styles.
24
+ - Synchronize the formula bar with Tabulator keyboard navigation and selection.
25
+ - Preserve live-demo cell identities after editing so arrow and Tab navigation remain reliable.
26
+ - Add browser regression coverage for editor layout, no-op edits and keyboard workflows.
27
+ - Include the live documentation playground in English, Simplified Chinese and Belarusian.
28
+
29
+ ## 0.3.0a1 — 2026-10-24
30
+
31
+ - Initial Django package, explicit Admin registration, precompiled static assets.
32
+ - Spreadsheet range editing, local undo/redo, safe atomic saves and row fingerprints.
33
+ - Permission-aware search, grouped filters, sorting, snapshots and Admin switching.
34
+ - Bounded Python/TypeScript formula engines with shared golden fixtures.
35
+ - Immutable bulk previews, confirmation, audit, idempotency and background adapter contract.
36
+ - Demo project, migrations, role/cleanup commands, CI and packaging checks.
37
+
38
+ Version 0.3.0a1 combined the planned v0.1–v0.3 increments and introduced the first
39
+ published schema. Later releases preserve its forward migration path.
@@ -0,0 +1,18 @@
1
+ # Contributing
2
+
3
+ Use Python 3.11+ (3.12+ with Django 6.x) and Node 22. Install `.[test]`, then run
4
+ `npm ci` inside frontend. Build assets with `npm run build` and include both source
5
+ and generated assets in changes. Never require npm in consuming Django projects.
6
+
7
+ Run pytest, ruff, Vitest and Playwright as described in README. Formula semantics
8
+ changes must add fixtures to tests/formula_cases.json and pass both runtimes.
9
+ Use actual transactional tests with separate connections for concurrency changes.
10
+ Database-specific behavior must be exercised by the PostgreSQL/MySQL CI jobs.
11
+
12
+ Run makemigrations for schema changes. Do not rewrite released migrations. Preserve
13
+ permission checks on every API/worker entry point and safe saves by default.
14
+ Do not silently broaden a preview's members or automatically replay failed items.
15
+
16
+ Update docs and CHANGELOG for public interfaces. Add dependency license notices when
17
+ bundling new assets. Avoid committing local credentials, demo databases and generated
18
+ test reports. The demo's explicit test credentials must not be used in production.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 django-modelsheet contributors
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,14 @@
1
+ include LICENSE README.md CHANGELOG.md CONTRIBUTING.md SECURITY.md
2
+ recursive-include modelsheet/static *
3
+ recursive-include modelsheet/templates *.html
4
+ recursive-include modelsheet/locale *.po *.mo
5
+ recursive-include docs *.md *.json
6
+ recursive-include frontend *.ts *.json *.html *.css
7
+ prune frontend/node_modules
8
+ prune frontend/test-results
9
+ prune frontend/playwright-report
10
+ recursive-include tests *.py *.json
11
+ recursive-include demo *.py
12
+ recursive-include scripts *.py
13
+ recursive-include .github/workflows *.yml
14
+ include manage.py
@@ -0,0 +1,210 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-modelsheet
3
+ Version: 0.3.0
4
+ Summary: Spreadsheet editing, formulas and previewed bulk operations for Django Admin
5
+ License-Expression: MIT
6
+ Project-URL: Repository, https://github.com/svalench/django-modelsheet
7
+ Project-URL: Documentation, https://svalench.github.io/django-modelsheet/
8
+ Project-URL: Issues, https://github.com/svalench/django-modelsheet/issues
9
+ Project-URL: Changelog, https://github.com/svalench/django-modelsheet/blob/main/CHANGELOG.md
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Framework :: Django
12
+ Classifier: Framework :: Django :: 5.2
13
+ Classifier: Framework :: Django :: 6.0
14
+ Classifier: Framework :: Django :: 6.1
15
+ Classifier: Programming Language :: Python :: 3
16
+ Requires-Python: >=3.11
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: Django<6.2,>=5.2
20
+ Provides-Extra: test
21
+ Requires-Dist: pytest>=8; extra == "test"
22
+ Requires-Dist: pytest-django>=4.9; extra == "test"
23
+ Requires-Dist: pytest-timeout>=2; extra == "test"
24
+ Requires-Dist: build; extra == "test"
25
+ Requires-Dist: ruff; extra == "test"
26
+ Requires-Dist: playwright; extra == "test"
27
+ Requires-Dist: PyYAML>=6; extra == "test"
28
+ Provides-Extra: postgres
29
+ Requires-Dist: psycopg[binary]>=3.2; extra == "postgres"
30
+ Provides-Extra: mysql
31
+ Requires-Dist: mysqlclient>=2.2; extra == "mysql"
32
+ Dynamic: license-file
33
+
34
+ # django-modelsheet
35
+
36
+ Spreadsheet editing for explicitly registered Django Admin models: cell/range editing,
37
+ local undo/redo, Decimal formulas, server-side filters, and previewed bulk changes.
38
+
39
+ **0.3.0 is the first stable release.** [Release notes](https://github.com/svalench/django-modelsheet/releases/tag/v0.3.0) · [PyPI](https://pypi.org/project/django-modelsheet/0.3.0/)
40
+ The repository includes a working demo, compiled assets, tests, and a compatibility CI matrix.
41
+
42
+ **[Documentation website →](https://svalench.github.io/django-modelsheet/)** —
43
+ installation, examples, formulas, bulk operations and extension APIs in English, Simplified Chinese and Belarusian.
44
+
45
+ ## Quickstart
46
+
47
+ Install the stable release:
48
+
49
+ ```sh
50
+ pip install django-modelsheet==0.3.0
51
+ ```
52
+
53
+ ```python
54
+ # settings.py
55
+ INSTALLED_APPS += ["modelsheet"]
56
+
57
+ # SQLite only: required for safe writes; PostgreSQL/MySQL use row locks.
58
+ DATABASES["default"].setdefault("OPTIONS", {})["transaction_mode"] = "IMMEDIATE"
59
+ ```
60
+
61
+ ```python
62
+ # admin.py
63
+ from django.contrib import admin
64
+ from modelsheet.admin import ModelSheetAdmin
65
+ from .models import Product
66
+
67
+ @admin.register(Product)
68
+ class ProductAdmin(ModelSheetAdmin):
69
+ list_display = ("name", "price", "stock")
70
+ search_fields = ("name",)
71
+ sheet_fields = ("name", "price", "stock")
72
+ sheet_editable = ("price", "stock")
73
+ sheet_computed_fields = {"inventory_value": "=[price]*[stock]"}
74
+ ```
75
+
76
+ ```sh
77
+ python manage.py migrate
78
+ python manage.py collectstatic --noinput
79
+ python manage.py modelsheet_roles # optional: creates groups, assigns no users
80
+ ```
81
+
82
+ Registering `ModelSheetAdmin` enables the sheet; no model list in settings is needed.
83
+
84
+ Assign a group through Django Admin and mark the account as staff. Superusers can
85
+ use configured sheets immediately. Open **Spreadsheet** from the model list, or
86
+ visit `/admin/shop/product/sheet/`. No frontend build, CDN or extra URL include is
87
+ required in the consuming project. Admin's existing sessions and CSRF protection apply.
88
+
89
+ ## Upgrading to 0.3.0
90
+
91
+ Back up the database and pause writes/background workers. Install the new package,
92
+ run `python manage.py migrate` and `python manage.py collectstatic --noinput`, then
93
+ restart the application/workers and reload browser tabs. Migration `0002` preserves
94
+ history and operation items, but expires legacy unconfirmed previews: build a new
95
+ preview before confirming. Already confirmed runs retain their resume behavior.
96
+ New preview deadlines start when preparation completes and cannot be extended by
97
+ cancel/resume or settings changes. Pin `django-modelsheet==0.3.0`.
98
+
99
+ ## Using the sheet
100
+
101
+ - Double-click to edit; use the formula bar for a value or expression.
102
+ - Changes stay local until **Save**. Ctrl/Cmd+Z, Ctrl/Cmd+Y and Ctrl/Cmd+S operate on this buffer.
103
+ - Select a range, copy/paste TSV from Excel, or press Ctrl/Cmd+D to fill down.
104
+ - Readonly cells are skipped during paste with a notification. A save is atomic across all changed rows.
105
+ - Use **Sort** for ordered sort fields, or Alt+click a column header (Alt+Shift+click adds a field).
106
+ Ordinary header clicks select columns. Search and filters run on the server.
107
+ - **Bulk change** selects either highlighted page rows or every matching row, including other pages.
108
+ Build a preview, inspect its exact count/values, then confirm it. Editing inputs requires a new preview.
109
+ - **Ordinary Admin** is available only when its list can represent the same filter, ordering and page.
110
+
111
+ Numbers use a decimal point and dates use ISO 8601. Empty pasted cells become
112
+ NULL for nullable fields, otherwise empty text for text fields or a validation error.
113
+ Prefix text beginning with `=` with an apostrophe, for example `'=SUM(A1:A2)`.
114
+
115
+ ## Configuration
116
+
117
+ ```python
118
+ MODELSHEET = {
119
+ "page_size": 200,
120
+ "max_page_size": 500,
121
+ "max_save_rows": 500,
122
+ "count_mode": "exact", # exact | none (no approximate COUNT promise)
123
+ "bulk_background_threshold": 5000,
124
+ "max_bulk_rows": 100000,
125
+ "chunk_size": 200,
126
+ "snapshot_ttl_seconds": 1800,
127
+ "preview_ttl_seconds": 1800,
128
+ "history_retention_days": 365,
129
+ "max_operations_per_minute": 30,
130
+ "max_request_bytes": 1000000,
131
+ "formula": {"max_length": 500, "max_depth": 10, "max_steps": 10000, "timeout_ms": 250},
132
+ "background_adapter": None,
133
+ }
134
+ ```
135
+
136
+ Run `python manage.py modelsheet_cleanup` periodically through your scheduler.
137
+ It removes expired snapshots and terminal/unused-preview operations beyond retention.
138
+ Do not reuse old idempotency keys after their operation has been purged.
139
+
140
+ ## Permissions
141
+
142
+ Access requires `is_active`, `is_staff`, `modelsheet.open`, the model's standard
143
+ `view` permission, and `ModelAdmin.has_view_permission()`. Editing additionally
144
+ requires the standard `change` permission and `has_change_permission()`.
145
+
146
+ Package permission codenames include app/model identifiers:
147
+
148
+ ```text
149
+ modelsheet.view_field_shop_product_price
150
+ modelsheet.edit_field_shop_product_price
151
+ modelsheet.bulk_shop_product
152
+ modelsheet.history_shop_product
153
+ ```
154
+
155
+ `get_queryset(request)` bounds every read/write. Object-level Admin hooks and the
156
+ configured policy apply in addition. Hidden fields cannot be used in filters,
157
+ sorting, formulas or history. Field permissions never grant model-level editing.
158
+
159
+ Group templates are opt-in and additive: Viewer, Editor, Operator, Auditor and Admin.
160
+ They grant access to the configured sheet fields; review these grants before
161
+ assigning users, especially sensitive columns. They do not grant superuser status.
162
+
163
+ ## Development and demo
164
+
165
+ ```sh
166
+ python -m pip install -e '.[test]'
167
+ cd frontend
168
+ npm ci
169
+ npm run build
170
+ npm test
171
+ cd ..
172
+ python manage.py migrate
173
+ python manage.py seed_demo --create-user
174
+ python manage.py runserver
175
+ ```
176
+
177
+ The explicit `--create-user` option creates a local-only `admin` / `admin` account.
178
+ The demo settings are not production settings. Open
179
+ `http://127.0.0.1:8000/admin/shop/product/sheet/`.
180
+
181
+ ```sh
182
+ python -m pytest
183
+ python -m ruff check .
184
+ python -m build --no-isolation
185
+ cd frontend
186
+ npx playwright install chromium
187
+ npm run test:e2e
188
+ ```
189
+
190
+ Target matrix: Django 5.2 / Python 3.11–3.14; Django 6.0 and 6.1 / Python
191
+ 3.12–3.14; PostgreSQL, MySQL/InnoDB, SQLite. CI exercises valid combinations and
192
+ the same transactional contract across databases. Consult CI results before
193
+ treating a combination as verified; local results are recorded in `docs/validation.md`.
194
+
195
+ ## Boundaries
196
+
197
+ Safe mode calls `full_clean()` and the instance's `save()` by default, including
198
+ normal model signals. Custom `ModelAdmin.save_model()`, custom Admin forms,
199
+ `save_related()` and external effects need an explicit adapter. Snapshot fingerprints
200
+ cover concrete model fields, not all intermediate history or related-table contents.
201
+
202
+ Sheets use the `default` database. User models require no extra fields or inheritance.
203
+ Existing scalar fields are editable; FK fields can be displayed/filtered but FK/M2M
204
+ editors, server undo, file import/export, fast-save, cursor pagination and persistent
205
+ formulas are deferred. Large operations require your own background adapter.
206
+
207
+ See [formulas](docs/formulas.md), [extension API](docs/extensions.md),
208
+ [background processing](docs/background.md), [HTTP API](docs/api.md), and
209
+ [release procedure](docs/releasing.md). Bundled dependency notices are in
210
+ `modelsheet/static/modelsheet/THIRD_PARTY_LICENSES.txt`.