django-adr 0.1.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 (40) hide show
  1. django_adr-0.1.0/.github/workflows/ci.yml +92 -0
  2. django_adr-0.1.0/.gitignore +36 -0
  3. django_adr-0.1.0/.pre-commit-config.yaml +60 -0
  4. django_adr-0.1.0/CHANGELOG.md +25 -0
  5. django_adr-0.1.0/LICENSE +21 -0
  6. django_adr-0.1.0/Makefile +46 -0
  7. django_adr-0.1.0/PKG-INFO +176 -0
  8. django_adr-0.1.0/README.md +148 -0
  9. django_adr-0.1.0/django_adr/__init__.py +1 -0
  10. django_adr-0.1.0/django_adr/admin.py +22 -0
  11. django_adr-0.1.0/django_adr/api.py +14 -0
  12. django_adr-0.1.0/django_adr/apps.py +11 -0
  13. django_adr-0.1.0/django_adr/locale/en/LC_MESSAGES/django.mo +0 -0
  14. django_adr-0.1.0/django_adr/locale/en/LC_MESSAGES/django.po +147 -0
  15. django_adr-0.1.0/django_adr/management/__init__.py +1 -0
  16. django_adr-0.1.0/django_adr/management/commands/__init__.py +1 -0
  17. django_adr-0.1.0/django_adr/management/commands/create_adr.py +73 -0
  18. django_adr-0.1.0/django_adr/management/commands/export_adrs.py +63 -0
  19. django_adr-0.1.0/django_adr/migrations/0001_initial.py +67 -0
  20. django_adr-0.1.0/django_adr/migrations/__init__.py +0 -0
  21. django_adr-0.1.0/django_adr/models.py +88 -0
  22. django_adr-0.1.0/django_adr/serializers.py +37 -0
  23. django_adr-0.1.0/django_adr/templates/django_adr/adr_detail.html +35 -0
  24. django_adr-0.1.0/django_adr/templates/django_adr/adr_list.html +40 -0
  25. django_adr-0.1.0/django_adr/templates/django_adr/base_django_adr.html +12 -0
  26. django_adr-0.1.0/django_adr/urls.py +18 -0
  27. django_adr-0.1.0/django_adr/utils.py +10 -0
  28. django_adr-0.1.0/django_adr/views.py +49 -0
  29. django_adr-0.1.0/manage.py +17 -0
  30. django_adr-0.1.0/pyproject.toml +101 -0
  31. django_adr-0.1.0/tests/__init__.py +1 -0
  32. django_adr-0.1.0/tests/settings.py +41 -0
  33. django_adr-0.1.0/tests/test_admin.py +47 -0
  34. django_adr-0.1.0/tests/test_api.py +100 -0
  35. django_adr-0.1.0/tests/test_commands.py +88 -0
  36. django_adr-0.1.0/tests/test_export.py +55 -0
  37. django_adr-0.1.0/tests/test_models.py +159 -0
  38. django_adr-0.1.0/tests/test_views.py +123 -0
  39. django_adr-0.1.0/tests/urls.py +9 -0
  40. django_adr-0.1.0/uv.lock +334 -0
@@ -0,0 +1,92 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ concurrency:
8
+ group: ci-${{ github.ref }}
9
+ cancel-in-progress: true
10
+
11
+ jobs:
12
+ validate:
13
+ name: Validate
14
+ runs-on: ubuntu-24.04
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
18
+
19
+ - name: Validate
20
+ uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4
21
+
22
+ test:
23
+ name: Test
24
+ runs-on: ubuntu-24.04
25
+ needs: [validate]
26
+
27
+ steps:
28
+ - name: Checkout
29
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
30
+
31
+ - name: Install uv
32
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
33
+ with:
34
+ enable-cache: true
35
+ python-version: "3.12"
36
+
37
+ - name: Install dependencies
38
+ run: uv sync --frozen --group test
39
+
40
+ - name: Test
41
+ run: |
42
+ uv run coverage run manage.py test tests --buffer --durations 10 --noinput --parallel --shuffle --timing
43
+ uv run coverage combine
44
+ uv run coverage report
45
+
46
+ build:
47
+ name: Build
48
+ runs-on: ubuntu-24.04
49
+ needs: [validate, test]
50
+
51
+ steps:
52
+ - name: Checkout
53
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
54
+
55
+ - name: Install uv
56
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
57
+ with:
58
+ enable-cache: true
59
+
60
+ - name: Build distributions
61
+ run: |
62
+ uv build
63
+ ls dist/
64
+
65
+ - name: Upload distributions
66
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
67
+ with:
68
+ name: dist
69
+ path: dist/
70
+
71
+ publish:
72
+ name: Publish to PyPI
73
+ runs-on: ubuntu-24.04
74
+ needs: [build]
75
+ if: startsWith(github.ref, 'refs/tags/v')
76
+ environment: release
77
+
78
+ permissions:
79
+ id-token: write
80
+
81
+ steps:
82
+ - name: Download distributions
83
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
84
+ with:
85
+ name: dist
86
+ path: dist/
87
+
88
+ - name: Install uv
89
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
90
+
91
+ - name: Publish to PyPI
92
+ run: uv publish
@@ -0,0 +1,36 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.egg
11
+
12
+ # Environments
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # Unit test / coverage reports
18
+ .coverage*
19
+ .coverages/
20
+ .pytest_cache/
21
+ htmlcov/
22
+ *.cover
23
+
24
+ # Django
25
+ *.log
26
+ db.sqlite3
27
+
28
+ # Ruff
29
+ .ruff_cache/
30
+
31
+ # macOS
32
+ .DS_Store
33
+
34
+ # IDEs
35
+ .idea/
36
+ .vscode/
@@ -0,0 +1,60 @@
1
+ default_language_version:
2
+ python: python3.12
3
+ repos:
4
+ - repo: https://github.com/pre-commit/pre-commit-hooks
5
+ rev: v6.0.0
6
+ hooks:
7
+ - id: check-added-large-files
8
+ args: ["--maxkb=1024"]
9
+ - id: check-case-conflict
10
+ - id: check-docstring-first
11
+ - id: check-json
12
+ - id: check-merge-conflict
13
+ - id: check-symlinks
14
+ - id: check-toml
15
+ - id: check-yaml
16
+ args: ["--allow-multiple-documents"]
17
+ - id: debug-statements
18
+ - id: detect-private-key
19
+ - id: end-of-file-fixer
20
+ - id: fix-byte-order-marker
21
+ - id: forbid-new-submodules
22
+ - id: mixed-line-ending
23
+ - id: trailing-whitespace
24
+ - repo: https://github.com/gitleaks/gitleaks
25
+ rev: v8.30.1
26
+ hooks:
27
+ - id: gitleaks
28
+ - repo: https://github.com/adhtruong/mirrors-typos
29
+ rev: v1.47.0
30
+ hooks:
31
+ - id: typos
32
+ - repo: https://github.com/asottile/pyupgrade
33
+ rev: v3.21.2
34
+ hooks:
35
+ - id: pyupgrade
36
+ args: [--py312-plus]
37
+ - repo: https://github.com/adamchainz/django-upgrade
38
+ rev: 1.30.0
39
+ hooks:
40
+ - id: django-upgrade
41
+ args: [--target-version, "4.2"]
42
+ - repo: https://github.com/UnknownPlatypus/djangofmt-pre-commit
43
+ rev: v0.2.9
44
+ hooks:
45
+ - id: djangofmt
46
+ - repo: https://github.com/astral-sh/ruff-pre-commit
47
+ rev: v0.15.15
48
+ hooks:
49
+ - id: ruff
50
+ args: [--fix]
51
+ - id: ruff-format
52
+ - repo: https://github.com/tox-dev/pyproject-fmt
53
+ rev: v2.23.0
54
+ hooks:
55
+ - id: pyproject-fmt
56
+ - repo: https://github.com/pycqa/bandit
57
+ rev: 1.9.4
58
+ hooks:
59
+ - id: bandit
60
+ args: ["-c", "pyproject.toml"]
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - `ADR` model with auto-assigned sequential `number`, `title`, `status`, `date`, `context`, `decision`, `consequences`, and `superseded_by` self-reference
13
+ - Status lifecycle: `proposed`, `accepted`, `deprecated`, `superseded`, `rejected`
14
+ - `clean()` validation enforcing consistency between `status` and `superseded_by`
15
+ - Markdown rendering for `context`, `decision`, and `consequences` via `mistune`
16
+ - `status` filter on HTML list view (`?status=`)
17
+ - Django admin interface with custom fieldsets
18
+ - Read-only REST API (`djangorestframework`) with `superseded_by` exposed as ADR number
19
+ - Management command `create_adr` with optional `--supersedes` flag for atomic supersession
20
+ - Management command `export_adrs` to export ADRs as Markdown files
21
+ - Internationalization support (i18n) with English translations included
22
+ - GitHub Actions CI: `validate` → `build` on every push; `publish` to PyPI on `v*` tags via OIDC Trusted Publisher
23
+ - `uv` for dependency management and task running
24
+ - `Makefile` targets: `help`, `install`, `messages`, `migrate`, `migrations`, `showoutdated`, `test`, `update`, `validate`
25
+ - Pre-commit hooks: `ruff`, `ruff-format`, `pyupgrade`, `django-upgrade`, `djangofmt`, `pyproject-fmt`, `bandit`, `gitleaks`, `typos`
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Niccolò Mineo
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,46 @@
1
+ .DEFAULT_GOAL := help
2
+
3
+ .PHONY: install
4
+ install: ## Install all dev dependencies
5
+ uv sync --group dev
6
+
7
+ .PHONY: help
8
+ help: ## Show this help
9
+ @echo "[Help] Makefile list commands:"
10
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
11
+
12
+ .PHONY: messages
13
+ messages: ## Extract and compile i18n translation strings
14
+ uv run manage.py makemessages --add-location file --ignore .venv --locale en $(ARGS)
15
+ uv run manage.py compilemessages --ignore .venv $(ARGS)
16
+
17
+ .PHONY: migrate
18
+ migrate: ## Apply database migrations
19
+ uv run manage.py migrate --noinput $(ARGS)
20
+
21
+ .PHONY: migrations
22
+ migrations: ## Generate new Django migration files
23
+ uv run manage.py makemigrations --no-header $(ARGS)
24
+
25
+ .PHONY: showoutdated
26
+ showoutdated: ## Show outdated dependencies (Python, prek)
27
+ uv tree --all-groups --outdated | grep --color=always "(latest:.*)" || true
28
+ uv run prek auto-update --dry-run
29
+
30
+ .PHONY: test
31
+ test: ## Run tests with coverage
32
+ uv run coverage run manage.py test tests --buffer --durations 10 --noinput --parallel --shuffle --timing
33
+ uv run coverage combine
34
+ uv run coverage html
35
+ uv run coverage report
36
+
37
+ .PHONY: update
38
+ update: ## Update dependencies, pre-commit hooks and GitHub Actions versions
39
+ uv lock --upgrade
40
+ uv sync --group dev
41
+ uv run prek autoupdate
42
+ gha-update
43
+
44
+ .PHONY: validate
45
+ validate: ## Run pre-commit hooks on all files
46
+ uv run prek run --all-files
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-adr
3
+ Version: 0.1.0
4
+ Summary: A Django reusable package to manage Architectural Decision Records.
5
+ Project-URL: homepage, https://niccolomineo.com
6
+ Author: Niccolò Mineo
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Framework :: Django
12
+ Classifier: Framework :: Django :: 4.2
13
+ Classifier: Framework :: Django :: 5.0
14
+ Classifier: Framework :: Django :: 5.1
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Internet :: WWW/HTTP
22
+ Classifier: Topic :: Software Development :: Documentation
23
+ Requires-Python: >=3.12
24
+ Requires-Dist: django>=4.2
25
+ Requires-Dist: djangorestframework>=3.14
26
+ Requires-Dist: mistune>=3
27
+ Description-Content-Type: text/markdown
28
+
29
+ # django-adr
30
+
31
+ A Django reusable package to manage **[Architectural Decision Records (ADR)](https://niccolomineo.com/articles/django-architectural-decisions/)**.
32
+
33
+ > **Warning:** This package is not production ready. APIs and data models may change between versions.
34
+
35
+ ## Features
36
+
37
+ - Django Admin interface to create and manage ADRs
38
+ - HTML list and detail views with status filtering
39
+ - Read-only REST API (Django REST Framework) with pre-rendered Markdown HTML fields
40
+ - Management command `create_adr` to create ADRs from the CLI, with optional `--supersedes` to mark an existing ADR as superseded in one step
41
+ - Management command `export_adrs` to export all ADRs as Markdown files
42
+ - Markdown support for context, decision, and consequences fields
43
+ - Internationalization (i18n) support — English locale included
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install django-adr
49
+ ```
50
+
51
+ Add to `INSTALLED_APPS`:
52
+
53
+ ```python
54
+ INSTALLED_APPS = [
55
+ ...
56
+ "django_adr",
57
+ ]
58
+ ```
59
+
60
+ Include the URLs:
61
+
62
+ ```python
63
+ from django.urls import include, path
64
+
65
+ urlpatterns = [
66
+ ...
67
+ path("adrs/", include("django_adr.urls", namespace="django_adr")),
68
+ ]
69
+ ```
70
+
71
+ Run migrations:
72
+
73
+ ```bash
74
+ python manage.py migrate
75
+ ```
76
+
77
+ ## Usage
78
+
79
+ ### Admin
80
+
81
+ Visit `/admin/django_adr/adr/` to manage ADRs through the Django admin.
82
+
83
+ ### HTML views
84
+
85
+ - `/adrs/` — list all ADRs
86
+ - `/adrs/?status=accepted` — filter by status
87
+ - `/adrs/<number>/` — view a single ADR
88
+
89
+ ### REST API
90
+
91
+ - `GET /adrs/api/adrs/` — list all ADRs
92
+ - `GET /adrs/api/adrs/<number>/` — retrieve a single ADR
93
+
94
+ ### Management commands
95
+
96
+ Create a new ADR:
97
+
98
+ ```bash
99
+ python manage.py create_adr "Use PostgreSQL" \
100
+ --context="We need a relational database." \
101
+ --decision="Use PostgreSQL." \
102
+ --consequences="Team must know SQL."
103
+ ```
104
+
105
+ Create a new ADR and supersede an existing one in a single step:
106
+
107
+ ```bash
108
+ python manage.py create_adr "Use CockroachDB" --supersedes=3
109
+ ```
110
+
111
+ This creates the new ADR and automatically marks ADR-0003 as `Superseded`.
112
+
113
+ Export all ADRs as Markdown files:
114
+
115
+ ```bash
116
+ python manage.py export_adrs --output-dir=docs/adr
117
+ ```
118
+
119
+ Each ADR is written to `<output-dir>/<number>-<slug>.md`.
120
+
121
+ ## ADR statuses
122
+
123
+ | Status | Description |
124
+ |--------|-------------|
125
+ | `proposed` | Under discussion |
126
+ | `accepted` | Agreed and in effect |
127
+ | `deprecated` | No longer relevant |
128
+ | `superseded` | Replaced by a newer ADR |
129
+ | `rejected` | Considered and not adopted |
130
+
131
+ ## Protecting the views
132
+
133
+ The HTML views and REST API are public by default. The package does not enforce any authentication strategy — that is left to the host project.
134
+
135
+ **HTML views** — in `urls.py`, wrap the URL include with `login_required`:
136
+
137
+ ```python
138
+ from django.contrib.auth.decorators import login_required
139
+ from django.urls import include, path
140
+
141
+ urlpatterns = [
142
+ path("adrs/", login_required(include("django_adr.urls", namespace="django_adr"))),
143
+ ]
144
+ ```
145
+
146
+ **REST API** — set `DEFAULT_PERMISSION_CLASSES` in `settings.py`:
147
+
148
+ ```python
149
+ REST_FRAMEWORK = {
150
+ "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
151
+ }
152
+ ```
153
+
154
+ Or scope it to the ADR router only by subclassing `ADRViewSet`:
155
+
156
+ ```python
157
+ from django_adr.api import ADRViewSet
158
+ from rest_framework.permissions import IsAuthenticated
159
+
160
+ class ProtectedADRViewSet(ADRViewSet):
161
+ permission_classes = [IsAuthenticated]
162
+ ```
163
+
164
+ ## Translations
165
+
166
+ All user-facing strings are translatable. The package ships with an English locale. To generate translations for your project:
167
+
168
+ ```bash
169
+ python manage.py makemessages -l it
170
+ ```
171
+
172
+ Ensure `USE_I18N = True` in your project settings.
173
+
174
+ ## License
175
+
176
+ MIT
@@ -0,0 +1,148 @@
1
+ # django-adr
2
+
3
+ A Django reusable package to manage **[Architectural Decision Records (ADR)](https://niccolomineo.com/articles/django-architectural-decisions/)**.
4
+
5
+ > **Warning:** This package is not production ready. APIs and data models may change between versions.
6
+
7
+ ## Features
8
+
9
+ - Django Admin interface to create and manage ADRs
10
+ - HTML list and detail views with status filtering
11
+ - Read-only REST API (Django REST Framework) with pre-rendered Markdown HTML fields
12
+ - Management command `create_adr` to create ADRs from the CLI, with optional `--supersedes` to mark an existing ADR as superseded in one step
13
+ - Management command `export_adrs` to export all ADRs as Markdown files
14
+ - Markdown support for context, decision, and consequences fields
15
+ - Internationalization (i18n) support — English locale included
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install django-adr
21
+ ```
22
+
23
+ Add to `INSTALLED_APPS`:
24
+
25
+ ```python
26
+ INSTALLED_APPS = [
27
+ ...
28
+ "django_adr",
29
+ ]
30
+ ```
31
+
32
+ Include the URLs:
33
+
34
+ ```python
35
+ from django.urls import include, path
36
+
37
+ urlpatterns = [
38
+ ...
39
+ path("adrs/", include("django_adr.urls", namespace="django_adr")),
40
+ ]
41
+ ```
42
+
43
+ Run migrations:
44
+
45
+ ```bash
46
+ python manage.py migrate
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ ### Admin
52
+
53
+ Visit `/admin/django_adr/adr/` to manage ADRs through the Django admin.
54
+
55
+ ### HTML views
56
+
57
+ - `/adrs/` — list all ADRs
58
+ - `/adrs/?status=accepted` — filter by status
59
+ - `/adrs/<number>/` — view a single ADR
60
+
61
+ ### REST API
62
+
63
+ - `GET /adrs/api/adrs/` — list all ADRs
64
+ - `GET /adrs/api/adrs/<number>/` — retrieve a single ADR
65
+
66
+ ### Management commands
67
+
68
+ Create a new ADR:
69
+
70
+ ```bash
71
+ python manage.py create_adr "Use PostgreSQL" \
72
+ --context="We need a relational database." \
73
+ --decision="Use PostgreSQL." \
74
+ --consequences="Team must know SQL."
75
+ ```
76
+
77
+ Create a new ADR and supersede an existing one in a single step:
78
+
79
+ ```bash
80
+ python manage.py create_adr "Use CockroachDB" --supersedes=3
81
+ ```
82
+
83
+ This creates the new ADR and automatically marks ADR-0003 as `Superseded`.
84
+
85
+ Export all ADRs as Markdown files:
86
+
87
+ ```bash
88
+ python manage.py export_adrs --output-dir=docs/adr
89
+ ```
90
+
91
+ Each ADR is written to `<output-dir>/<number>-<slug>.md`.
92
+
93
+ ## ADR statuses
94
+
95
+ | Status | Description |
96
+ |--------|-------------|
97
+ | `proposed` | Under discussion |
98
+ | `accepted` | Agreed and in effect |
99
+ | `deprecated` | No longer relevant |
100
+ | `superseded` | Replaced by a newer ADR |
101
+ | `rejected` | Considered and not adopted |
102
+
103
+ ## Protecting the views
104
+
105
+ The HTML views and REST API are public by default. The package does not enforce any authentication strategy — that is left to the host project.
106
+
107
+ **HTML views** — in `urls.py`, wrap the URL include with `login_required`:
108
+
109
+ ```python
110
+ from django.contrib.auth.decorators import login_required
111
+ from django.urls import include, path
112
+
113
+ urlpatterns = [
114
+ path("adrs/", login_required(include("django_adr.urls", namespace="django_adr"))),
115
+ ]
116
+ ```
117
+
118
+ **REST API** — set `DEFAULT_PERMISSION_CLASSES` in `settings.py`:
119
+
120
+ ```python
121
+ REST_FRAMEWORK = {
122
+ "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
123
+ }
124
+ ```
125
+
126
+ Or scope it to the ADR router only by subclassing `ADRViewSet`:
127
+
128
+ ```python
129
+ from django_adr.api import ADRViewSet
130
+ from rest_framework.permissions import IsAuthenticated
131
+
132
+ class ProtectedADRViewSet(ADRViewSet):
133
+ permission_classes = [IsAuthenticated]
134
+ ```
135
+
136
+ ## Translations
137
+
138
+ All user-facing strings are translatable. The package ships with an English locale. To generate translations for your project:
139
+
140
+ ```bash
141
+ python manage.py makemessages -l it
142
+ ```
143
+
144
+ Ensure `USE_I18N = True` in your project settings.
145
+
146
+ ## License
147
+
148
+ MIT
@@ -0,0 +1 @@
1
+ """Django ADR — a package to manage Architectural Decision Records."""
@@ -0,0 +1,22 @@
1
+ """Django admin configuration for ADRs."""
2
+
3
+ from django.contrib import admin
4
+ from django.utils.translation import gettext_lazy as _
5
+
6
+ from django_adr.models import ADR
7
+
8
+
9
+ @admin.register(ADR)
10
+ class ADRAdmin(admin.ModelAdmin):
11
+ """Admin interface for ADR."""
12
+
13
+ list_display = ("number", "title", "status", "date")
14
+ list_filter = ("status",)
15
+ search_fields = ("title", "context", "decision", "consequences")
16
+ readonly_fields = ("number", "date")
17
+ fieldsets = (
18
+ (None, {"fields": ("number", "title", "status", "date", "superseded_by")}),
19
+ (_("Context"), {"fields": ("context",)}),
20
+ (_("Decision"), {"fields": ("decision",)}),
21
+ (_("Consequences"), {"fields": ("consequences",)}),
22
+ )
@@ -0,0 +1,14 @@
1
+ """DRF ViewSets for ADRs."""
2
+
3
+ from rest_framework.viewsets import ReadOnlyModelViewSet
4
+
5
+ from django_adr.models import ADR
6
+ from django_adr.serializers import ADRSerializer
7
+
8
+
9
+ class ADRViewSet(ReadOnlyModelViewSet):
10
+ """Provide read-only API access to ADRs."""
11
+
12
+ queryset = ADR.objects.select_related("superseded_by").all()
13
+ serializer_class = ADRSerializer
14
+ lookup_field = "number"
@@ -0,0 +1,11 @@
1
+ """Django ADR application configuration."""
2
+
3
+ from django.apps import AppConfig
4
+ from django.utils.translation import gettext_lazy as _
5
+
6
+
7
+ class DjangoAdrConfig(AppConfig):
8
+ """Django ADR application configuration."""
9
+
10
+ name = "django_adr"
11
+ verbose_name = _("Architectural Decision Records")