django-htmx-views 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gavin Burnell
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
2
+ include README.md
3
+ include UPSTREAM_COMPARISON.md
4
+ recursive-include htmx_views/templates *.html
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-htmx-views
3
+ Version: 0.1.0
4
+ Summary: Reusable Django view services for HTMX-enabled applications
5
+ Author: Gavin Burnell
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/gb119/django-htmx-views
8
+ Project-URL: Repository, https://github.com/gb119/django-htmx-views
9
+ Project-URL: Issues, https://github.com/gb119/django-htmx-views/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Framework :: Django
12
+ Classifier: Framework :: Django :: 4.2
13
+ Classifier: Framework :: Django :: 5.0
14
+ Classifier: Framework :: Django :: 5.1
15
+ Classifier: Framework :: Django :: 5.2
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Topic :: Internet :: WWW/HTTP
26
+ Requires-Python: >=3.10
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: Django>=4.2
30
+ Requires-Dist: django-htmx>=1.17
31
+ Provides-Extra: docs
32
+ Requires-Dist: Sphinx<9,>=7; extra == "docs"
33
+ Requires-Dist: django-ajax-selects>=2.2; extra == "docs"
34
+ Requires-Dist: sphinx-better-theme>=0.1.5; extra == "docs"
35
+ Provides-Extra: linked-selects
36
+ Requires-Dist: django-ajax-selects>=2.2; extra == "linked-selects"
37
+ Provides-Extra: test
38
+ Requires-Dist: build>=1.2; extra == "test"
39
+ Requires-Dist: django-ajax-selects>=2.2; extra == "test"
40
+ Requires-Dist: pytest>=8; extra == "test"
41
+ Requires-Dist: pytest-django>=4.8; extra == "test"
42
+ Requires-Dist: tomli>=2; python_version < "3.11" and extra == "test"
43
+ Requires-Dist: twine>=5; extra == "test"
44
+ Dynamic: license-file
45
+
46
+ # django-htmx-views
47
+
48
+ Reusable Django view mixins and widgets for building HTMX-enabled applications.
49
+ This package extracts the `htmx_views` app used by
50
+ [`gb119/labman`](https://github.com/gb119/labman) and
51
+ [`uolphysicsteaching/phas_vitals`](https://github.com/uolphysicsteaching/phas_vitals)
52
+ so that the implementation can be installed and maintained independently.
53
+
54
+ The initial package source is an exact copy of the newer `phas_vitals`
55
+ implementation at commit
56
+ [`1008bc4`](https://github.com/uolphysicsteaching/phas_vitals/commit/1008bc475a28a0ccca40df8769ad6902b68edebc).
57
+ The two upstream apps were compared before extraction and are not currently
58
+ identical; see [UPSTREAM_COMPARISON.md](UPSTREAM_COMPARISON.md) for the
59
+ verification details.
60
+
61
+ ## Features
62
+
63
+ - HTMX-aware dispatch for Django class-based views.
64
+ - Routing by HTMX trigger name, trigger ID, or target ID.
65
+ - HTMX-specific templates, context data, and context object names.
66
+ - HTMX-aware form-valid and form-invalid handlers.
67
+ - Optional linked `<select>` widgets backed by `django-ajax-selects`.
68
+
69
+ ## Installation
70
+
71
+ Install the core package:
72
+
73
+ ```console
74
+ python -m pip install django-htmx-views
75
+ ```
76
+
77
+ Install linked-select support as well:
78
+
79
+ ```console
80
+ python -m pip install "django-htmx-views[linked-selects]"
81
+ ```
82
+
83
+ Add the app and `django-htmx` middleware to the host project's settings:
84
+
85
+ ```python
86
+ INSTALLED_APPS = [
87
+ # ...
88
+ "htmx_views",
89
+ ]
90
+
91
+ MIDDLEWARE = [
92
+ # ...
93
+ "django_htmx.middleware.HtmxMiddleware",
94
+ ]
95
+ ```
96
+
97
+ ## HTMX-aware views
98
+
99
+ Importing `htmx_views.views` installs the existing HTMX-aware dispatch hook on
100
+ Django's base `View` class. Mix `HTMXProcessMixin` into a class-based view to
101
+ route HTMX requests to element-specific handlers:
102
+
103
+ ```python
104
+ from django.http import HttpResponse
105
+ from django.views.generic import TemplateView
106
+
107
+ from htmx_views.views import HTMXProcessMixin
108
+
109
+
110
+ class ResultsView(HTMXProcessMixin, TemplateView):
111
+ template_name = "results/page.html"
112
+ template_name_results = "results/_table.html"
113
+
114
+ def htmx_get_refresh(self, request, *args, **kwargs):
115
+ return HttpResponse("refreshed")
116
+ ```
117
+
118
+ For an HTMX `GET`, the mixin looks for handlers using the request's
119
+ `trigger_name`, `trigger`, and `target`, in that order. Element names are
120
+ lowercased and stripped of characters other than letters, numbers, and
121
+ underscores. The same convention is available for `DELETE`, `PATCH`, `POST`,
122
+ and `PUT`.
123
+
124
+ `HTMXFormMixin` adds equivalent `htmx_form_valid_<element>` and
125
+ `htmx_form_invalid_<element>` hooks for form views.
126
+
127
+ ## Linked selects
128
+
129
+ Linked selects are optional because they require `django-ajax-selects`. After
130
+ installing the `linked-selects` extra, include the package URLs:
131
+
132
+ ```python
133
+ from django.urls import include, path
134
+
135
+ urlpatterns = [
136
+ path(
137
+ "htmx-views/",
138
+ include(("htmx_views.urls", "htmx_views"), namespace="htmx_views"),
139
+ ),
140
+ ]
141
+ ```
142
+
143
+ Then use a registered `django-ajax-selects` lookup:
144
+
145
+ ```python
146
+ from django import forms
147
+
148
+ from htmx_views.widgets import HTMXSelectWidget
149
+
150
+
151
+ class EquipmentForm(forms.Form):
152
+ module = forms.ModelChoiceField(queryset=...)
153
+ category = forms.ModelChoiceField(
154
+ queryset=...,
155
+ widget=HTMXSelectWidget("categories", parent="module"),
156
+ )
157
+ ```
158
+
159
+ The linked-select endpoint runs the lookup's authorisation check before
160
+ querying it. Importing linked-select modules without the optional dependency
161
+ raises an actionable `ImportError`; the core view mixins remain usable.
162
+
163
+ ## Migrating an existing project
164
+
165
+ 1. Install this package and add `"htmx_views"` to `INSTALLED_APPS`.
166
+ 2. Replace imports beginning with `apps.htmx_views` with `htmx_views`.
167
+ 3. If linked selects are used, install the extra and include
168
+ `htmx_views.urls` under the `htmx_views` namespace.
169
+ 4. Remove the project's copied `apps/htmx_views` directory after its tests
170
+ pass against the package.
171
+
172
+ The former `htmx_views.views.LinkedSelectEndpointView` import remains available
173
+ for compatibility.
174
+
175
+ ## Development and builds
176
+
177
+ Create a development environment and run the tests:
178
+
179
+ ```console
180
+ python -m pip install -e ".[test,linked-selects]"
181
+ python -m pytest
182
+ ```
183
+
184
+ Build and validate the wheel and source distribution:
185
+
186
+ ```console
187
+ python -m build
188
+ python -m twine check dist/*
189
+ ```
190
+
191
+ Build the noarch Conda package with `conda-build`:
192
+
193
+ ```console
194
+ conda-build conda-recipe
195
+ ```
196
+
197
+ The GitHub Actions build workflow runs the tests and produces both Python and
198
+ Conda package artifacts.
199
+
200
+ ## Documentation
201
+
202
+ The full documentation is published at
203
+ [gb119.github.io/django-htmx-views](https://gb119.github.io/django-htmx-views/).
204
+
205
+ Build it locally with:
206
+
207
+ ```console
208
+ python -m pip install -e ".[docs]"
209
+ python -m sphinx -W --keep-going -b html docs/source docs/build/html
210
+ ```
211
+
212
+ The documentation workflow rebuilds and deploys GitHub Pages for published
213
+ releases and pre-releases, and can also be started manually.
214
+
215
+ ## Publishing a release
216
+
217
+ Creating a GitHub release, including a pre-release, runs the release workflow.
218
+ It verifies that the release tag (for example, `vX.Y.Z`) matches
219
+ `htmx_views.__version__`, reruns the tests, builds both package formats, and
220
+ publishes:
221
+
222
+ - the wheel and source distribution to PyPI;
223
+ - the noarch Conda package to the `phygbu` Anaconda channel with the `main`
224
+ label.
225
+
226
+ Configure these GitHub Actions repository secrets before publishing:
227
+
228
+ - `PYPI_TOKEN`: a PyPI API token authorised for `django-htmx-views`;
229
+ - `ANACONDA`: an Anaconda.org API token authorised to upload to `phygbu`.
230
+
231
+ The upload steps deliberately refuse to overwrite an existing Conda package.
232
+
233
+ ## License
234
+
235
+ MIT
@@ -0,0 +1,190 @@
1
+ # django-htmx-views
2
+
3
+ Reusable Django view mixins and widgets for building HTMX-enabled applications.
4
+ This package extracts the `htmx_views` app used by
5
+ [`gb119/labman`](https://github.com/gb119/labman) and
6
+ [`uolphysicsteaching/phas_vitals`](https://github.com/uolphysicsteaching/phas_vitals)
7
+ so that the implementation can be installed and maintained independently.
8
+
9
+ The initial package source is an exact copy of the newer `phas_vitals`
10
+ implementation at commit
11
+ [`1008bc4`](https://github.com/uolphysicsteaching/phas_vitals/commit/1008bc475a28a0ccca40df8769ad6902b68edebc).
12
+ The two upstream apps were compared before extraction and are not currently
13
+ identical; see [UPSTREAM_COMPARISON.md](UPSTREAM_COMPARISON.md) for the
14
+ verification details.
15
+
16
+ ## Features
17
+
18
+ - HTMX-aware dispatch for Django class-based views.
19
+ - Routing by HTMX trigger name, trigger ID, or target ID.
20
+ - HTMX-specific templates, context data, and context object names.
21
+ - HTMX-aware form-valid and form-invalid handlers.
22
+ - Optional linked `<select>` widgets backed by `django-ajax-selects`.
23
+
24
+ ## Installation
25
+
26
+ Install the core package:
27
+
28
+ ```console
29
+ python -m pip install django-htmx-views
30
+ ```
31
+
32
+ Install linked-select support as well:
33
+
34
+ ```console
35
+ python -m pip install "django-htmx-views[linked-selects]"
36
+ ```
37
+
38
+ Add the app and `django-htmx` middleware to the host project's settings:
39
+
40
+ ```python
41
+ INSTALLED_APPS = [
42
+ # ...
43
+ "htmx_views",
44
+ ]
45
+
46
+ MIDDLEWARE = [
47
+ # ...
48
+ "django_htmx.middleware.HtmxMiddleware",
49
+ ]
50
+ ```
51
+
52
+ ## HTMX-aware views
53
+
54
+ Importing `htmx_views.views` installs the existing HTMX-aware dispatch hook on
55
+ Django's base `View` class. Mix `HTMXProcessMixin` into a class-based view to
56
+ route HTMX requests to element-specific handlers:
57
+
58
+ ```python
59
+ from django.http import HttpResponse
60
+ from django.views.generic import TemplateView
61
+
62
+ from htmx_views.views import HTMXProcessMixin
63
+
64
+
65
+ class ResultsView(HTMXProcessMixin, TemplateView):
66
+ template_name = "results/page.html"
67
+ template_name_results = "results/_table.html"
68
+
69
+ def htmx_get_refresh(self, request, *args, **kwargs):
70
+ return HttpResponse("refreshed")
71
+ ```
72
+
73
+ For an HTMX `GET`, the mixin looks for handlers using the request's
74
+ `trigger_name`, `trigger`, and `target`, in that order. Element names are
75
+ lowercased and stripped of characters other than letters, numbers, and
76
+ underscores. The same convention is available for `DELETE`, `PATCH`, `POST`,
77
+ and `PUT`.
78
+
79
+ `HTMXFormMixin` adds equivalent `htmx_form_valid_<element>` and
80
+ `htmx_form_invalid_<element>` hooks for form views.
81
+
82
+ ## Linked selects
83
+
84
+ Linked selects are optional because they require `django-ajax-selects`. After
85
+ installing the `linked-selects` extra, include the package URLs:
86
+
87
+ ```python
88
+ from django.urls import include, path
89
+
90
+ urlpatterns = [
91
+ path(
92
+ "htmx-views/",
93
+ include(("htmx_views.urls", "htmx_views"), namespace="htmx_views"),
94
+ ),
95
+ ]
96
+ ```
97
+
98
+ Then use a registered `django-ajax-selects` lookup:
99
+
100
+ ```python
101
+ from django import forms
102
+
103
+ from htmx_views.widgets import HTMXSelectWidget
104
+
105
+
106
+ class EquipmentForm(forms.Form):
107
+ module = forms.ModelChoiceField(queryset=...)
108
+ category = forms.ModelChoiceField(
109
+ queryset=...,
110
+ widget=HTMXSelectWidget("categories", parent="module"),
111
+ )
112
+ ```
113
+
114
+ The linked-select endpoint runs the lookup's authorisation check before
115
+ querying it. Importing linked-select modules without the optional dependency
116
+ raises an actionable `ImportError`; the core view mixins remain usable.
117
+
118
+ ## Migrating an existing project
119
+
120
+ 1. Install this package and add `"htmx_views"` to `INSTALLED_APPS`.
121
+ 2. Replace imports beginning with `apps.htmx_views` with `htmx_views`.
122
+ 3. If linked selects are used, install the extra and include
123
+ `htmx_views.urls` under the `htmx_views` namespace.
124
+ 4. Remove the project's copied `apps/htmx_views` directory after its tests
125
+ pass against the package.
126
+
127
+ The former `htmx_views.views.LinkedSelectEndpointView` import remains available
128
+ for compatibility.
129
+
130
+ ## Development and builds
131
+
132
+ Create a development environment and run the tests:
133
+
134
+ ```console
135
+ python -m pip install -e ".[test,linked-selects]"
136
+ python -m pytest
137
+ ```
138
+
139
+ Build and validate the wheel and source distribution:
140
+
141
+ ```console
142
+ python -m build
143
+ python -m twine check dist/*
144
+ ```
145
+
146
+ Build the noarch Conda package with `conda-build`:
147
+
148
+ ```console
149
+ conda-build conda-recipe
150
+ ```
151
+
152
+ The GitHub Actions build workflow runs the tests and produces both Python and
153
+ Conda package artifacts.
154
+
155
+ ## Documentation
156
+
157
+ The full documentation is published at
158
+ [gb119.github.io/django-htmx-views](https://gb119.github.io/django-htmx-views/).
159
+
160
+ Build it locally with:
161
+
162
+ ```console
163
+ python -m pip install -e ".[docs]"
164
+ python -m sphinx -W --keep-going -b html docs/source docs/build/html
165
+ ```
166
+
167
+ The documentation workflow rebuilds and deploys GitHub Pages for published
168
+ releases and pre-releases, and can also be started manually.
169
+
170
+ ## Publishing a release
171
+
172
+ Creating a GitHub release, including a pre-release, runs the release workflow.
173
+ It verifies that the release tag (for example, `vX.Y.Z`) matches
174
+ `htmx_views.__version__`, reruns the tests, builds both package formats, and
175
+ publishes:
176
+
177
+ - the wheel and source distribution to PyPI;
178
+ - the noarch Conda package to the `phygbu` Anaconda channel with the `main`
179
+ label.
180
+
181
+ Configure these GitHub Actions repository secrets before publishing:
182
+
183
+ - `PYPI_TOKEN`: a PyPI API token authorised for `django-htmx-views`;
184
+ - `ANACONDA`: an Anaconda.org API token authorised to upload to `phygbu`.
185
+
186
+ The upload steps deliberately refuse to overwrite an existing Conda package.
187
+
188
+ ## License
189
+
190
+ MIT
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-htmx-views
3
+ Version: 0.1.0
4
+ Summary: Reusable Django view services for HTMX-enabled applications
5
+ Author: Gavin Burnell
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/gb119/django-htmx-views
8
+ Project-URL: Repository, https://github.com/gb119/django-htmx-views
9
+ Project-URL: Issues, https://github.com/gb119/django-htmx-views/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Framework :: Django
12
+ Classifier: Framework :: Django :: 4.2
13
+ Classifier: Framework :: Django :: 5.0
14
+ Classifier: Framework :: Django :: 5.1
15
+ Classifier: Framework :: Django :: 5.2
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Topic :: Internet :: WWW/HTTP
26
+ Requires-Python: >=3.10
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: Django>=4.2
30
+ Requires-Dist: django-htmx>=1.17
31
+ Provides-Extra: docs
32
+ Requires-Dist: Sphinx<9,>=7; extra == "docs"
33
+ Requires-Dist: django-ajax-selects>=2.2; extra == "docs"
34
+ Requires-Dist: sphinx-better-theme>=0.1.5; extra == "docs"
35
+ Provides-Extra: linked-selects
36
+ Requires-Dist: django-ajax-selects>=2.2; extra == "linked-selects"
37
+ Provides-Extra: test
38
+ Requires-Dist: build>=1.2; extra == "test"
39
+ Requires-Dist: django-ajax-selects>=2.2; extra == "test"
40
+ Requires-Dist: pytest>=8; extra == "test"
41
+ Requires-Dist: pytest-django>=4.8; extra == "test"
42
+ Requires-Dist: tomli>=2; python_version < "3.11" and extra == "test"
43
+ Requires-Dist: twine>=5; extra == "test"
44
+ Dynamic: license-file
45
+
46
+ # django-htmx-views
47
+
48
+ Reusable Django view mixins and widgets for building HTMX-enabled applications.
49
+ This package extracts the `htmx_views` app used by
50
+ [`gb119/labman`](https://github.com/gb119/labman) and
51
+ [`uolphysicsteaching/phas_vitals`](https://github.com/uolphysicsteaching/phas_vitals)
52
+ so that the implementation can be installed and maintained independently.
53
+
54
+ The initial package source is an exact copy of the newer `phas_vitals`
55
+ implementation at commit
56
+ [`1008bc4`](https://github.com/uolphysicsteaching/phas_vitals/commit/1008bc475a28a0ccca40df8769ad6902b68edebc).
57
+ The two upstream apps were compared before extraction and are not currently
58
+ identical; see [UPSTREAM_COMPARISON.md](UPSTREAM_COMPARISON.md) for the
59
+ verification details.
60
+
61
+ ## Features
62
+
63
+ - HTMX-aware dispatch for Django class-based views.
64
+ - Routing by HTMX trigger name, trigger ID, or target ID.
65
+ - HTMX-specific templates, context data, and context object names.
66
+ - HTMX-aware form-valid and form-invalid handlers.
67
+ - Optional linked `<select>` widgets backed by `django-ajax-selects`.
68
+
69
+ ## Installation
70
+
71
+ Install the core package:
72
+
73
+ ```console
74
+ python -m pip install django-htmx-views
75
+ ```
76
+
77
+ Install linked-select support as well:
78
+
79
+ ```console
80
+ python -m pip install "django-htmx-views[linked-selects]"
81
+ ```
82
+
83
+ Add the app and `django-htmx` middleware to the host project's settings:
84
+
85
+ ```python
86
+ INSTALLED_APPS = [
87
+ # ...
88
+ "htmx_views",
89
+ ]
90
+
91
+ MIDDLEWARE = [
92
+ # ...
93
+ "django_htmx.middleware.HtmxMiddleware",
94
+ ]
95
+ ```
96
+
97
+ ## HTMX-aware views
98
+
99
+ Importing `htmx_views.views` installs the existing HTMX-aware dispatch hook on
100
+ Django's base `View` class. Mix `HTMXProcessMixin` into a class-based view to
101
+ route HTMX requests to element-specific handlers:
102
+
103
+ ```python
104
+ from django.http import HttpResponse
105
+ from django.views.generic import TemplateView
106
+
107
+ from htmx_views.views import HTMXProcessMixin
108
+
109
+
110
+ class ResultsView(HTMXProcessMixin, TemplateView):
111
+ template_name = "results/page.html"
112
+ template_name_results = "results/_table.html"
113
+
114
+ def htmx_get_refresh(self, request, *args, **kwargs):
115
+ return HttpResponse("refreshed")
116
+ ```
117
+
118
+ For an HTMX `GET`, the mixin looks for handlers using the request's
119
+ `trigger_name`, `trigger`, and `target`, in that order. Element names are
120
+ lowercased and stripped of characters other than letters, numbers, and
121
+ underscores. The same convention is available for `DELETE`, `PATCH`, `POST`,
122
+ and `PUT`.
123
+
124
+ `HTMXFormMixin` adds equivalent `htmx_form_valid_<element>` and
125
+ `htmx_form_invalid_<element>` hooks for form views.
126
+
127
+ ## Linked selects
128
+
129
+ Linked selects are optional because they require `django-ajax-selects`. After
130
+ installing the `linked-selects` extra, include the package URLs:
131
+
132
+ ```python
133
+ from django.urls import include, path
134
+
135
+ urlpatterns = [
136
+ path(
137
+ "htmx-views/",
138
+ include(("htmx_views.urls", "htmx_views"), namespace="htmx_views"),
139
+ ),
140
+ ]
141
+ ```
142
+
143
+ Then use a registered `django-ajax-selects` lookup:
144
+
145
+ ```python
146
+ from django import forms
147
+
148
+ from htmx_views.widgets import HTMXSelectWidget
149
+
150
+
151
+ class EquipmentForm(forms.Form):
152
+ module = forms.ModelChoiceField(queryset=...)
153
+ category = forms.ModelChoiceField(
154
+ queryset=...,
155
+ widget=HTMXSelectWidget("categories", parent="module"),
156
+ )
157
+ ```
158
+
159
+ The linked-select endpoint runs the lookup's authorisation check before
160
+ querying it. Importing linked-select modules without the optional dependency
161
+ raises an actionable `ImportError`; the core view mixins remain usable.
162
+
163
+ ## Migrating an existing project
164
+
165
+ 1. Install this package and add `"htmx_views"` to `INSTALLED_APPS`.
166
+ 2. Replace imports beginning with `apps.htmx_views` with `htmx_views`.
167
+ 3. If linked selects are used, install the extra and include
168
+ `htmx_views.urls` under the `htmx_views` namespace.
169
+ 4. Remove the project's copied `apps/htmx_views` directory after its tests
170
+ pass against the package.
171
+
172
+ The former `htmx_views.views.LinkedSelectEndpointView` import remains available
173
+ for compatibility.
174
+
175
+ ## Development and builds
176
+
177
+ Create a development environment and run the tests:
178
+
179
+ ```console
180
+ python -m pip install -e ".[test,linked-selects]"
181
+ python -m pytest
182
+ ```
183
+
184
+ Build and validate the wheel and source distribution:
185
+
186
+ ```console
187
+ python -m build
188
+ python -m twine check dist/*
189
+ ```
190
+
191
+ Build the noarch Conda package with `conda-build`:
192
+
193
+ ```console
194
+ conda-build conda-recipe
195
+ ```
196
+
197
+ The GitHub Actions build workflow runs the tests and produces both Python and
198
+ Conda package artifacts.
199
+
200
+ ## Documentation
201
+
202
+ The full documentation is published at
203
+ [gb119.github.io/django-htmx-views](https://gb119.github.io/django-htmx-views/).
204
+
205
+ Build it locally with:
206
+
207
+ ```console
208
+ python -m pip install -e ".[docs]"
209
+ python -m sphinx -W --keep-going -b html docs/source docs/build/html
210
+ ```
211
+
212
+ The documentation workflow rebuilds and deploys GitHub Pages for published
213
+ releases and pre-releases, and can also be started manually.
214
+
215
+ ## Publishing a release
216
+
217
+ Creating a GitHub release, including a pre-release, runs the release workflow.
218
+ It verifies that the release tag (for example, `vX.Y.Z`) matches
219
+ `htmx_views.__version__`, reruns the tests, builds both package formats, and
220
+ publishes:
221
+
222
+ - the wheel and source distribution to PyPI;
223
+ - the noarch Conda package to the `phygbu` Anaconda channel with the `main`
224
+ label.
225
+
226
+ Configure these GitHub Actions repository secrets before publishing:
227
+
228
+ - `PYPI_TOKEN`: a PyPI API token authorised for `django-htmx-views`;
229
+ - `ANACONDA`: an Anaconda.org API token authorised to upload to `phygbu`.
230
+
231
+ The upload steps deliberately refuse to overwrite an existing Conda package.
232
+
233
+ ## License
234
+
235
+ MIT