Extensions for using Django with htmx.
Improve your Django and Git skills with my books.
Please see https://django-htmx.readthedocs.io/ .
Extensions for using Django with htmx.
Home Page: https://django-htmx.readthedocs.io/
License: MIT License
Extensions for using Django with htmx.
Improve your Django and Git skills with my books.
Please see https://django-htmx.readthedocs.io/ .
The question may seem a little bit dumb, but are there some example usages of htmx to expand the django admin interface?
I did search a little bit and did not find any good examples. My company has been using django admin internally for data management and django REST interface with a frontend framework for displaying data for the customers.
I believe that a good way of expanding the django to use htmx and being a potential candidate to replace a frontend framework would start by improving the django admin with htmx functionalities. In this way I could gain confidence and knowledge on django-htmx and htmx, proving the worth of it.
I've implemented the following decorator and found it quite useful and just wanted to share.
The idea is to replicate the requires_http_methods
variants like requires_POST
, and redirect the user to a more relevant page if they (or their browser) somehow accidentally try to access a HTMX only endpoint. I've at least had some oddities of somehow getting there.
The decorator is pretty straight forward:
from functools import wraps
def requires_HTMX(redirect_url):
def decorator(func):
@wraps(func)
def inner(request, *args, **kwargs):
if not request.htmx:
_redirect_url = (
redirect_url(request, *args, **kwargs)
if callable(redirect_url) else redirect_url
)
return redirect(_redirect_url)
return func(request, *args, **kwargs)
return inner
return decorator
Basic usage:
@requires_HTMX(redirect_url=reverse("some-default-page"))
def htmx_only_view(request):
return render(request, "my_awesome_htmx_template.html")
but can also be used to redirect the user to a page which is relevant to the view:
def _get_post_url(request, post_id):
return reverse("post-detail", kwargs={"post_id": post_id})
@requires_HTMX(redirect_url=_get_post_url)
def render_post_form(request, post_id):
...
return render(request, "post_form.html", context=context)
which is quite useful when dealing with many HTMX only views tied together.
If this makes sense and you could see it work in django-htmx, I would love to do a PR with tests and documentation @adamchainz - if it is out of scope for the project that is also fine :)
It's just a small change, and would even break compatibility...
But I dare to suggest renaming it to "htmx" - just because {% load htmx %}
sounds clearer.
There is already a djhtmx
library which hast this tag - but anyway, both won't be installed together anyway.
Hi Adam!
Thanks for this useful package.
Here is a pattern that could be useful in several places (views or templates) :
if self.request.htmx and not self.request.htmx.boosted:
It helps pointing out when we really want to use a fragment template.
A real example here.
It could be interesting to add it a wrapper property, don’t know how to name it though (unboosted
???)...
If I would like to add it manually, it would mean patching HtmxDetail
, or make a custom middleware with a subclass of HtmxDetail
…
Hello!
i was successful with your /demo. but when i start a new django app and do this middleware change, it gives me an Error (WSGI..) . i am the only one? :)
Add the middleware:
MIDDLEWARE = [
...,
"django_htmx.HtmxMiddleware",
...,
]
I'd like to start using htmx (means I'm an htmx newbie). Is there a recommended way of handling messages created in views with code such as messages.success(request, 'All good')
?
Perhaps HtmxMiddleware
could check request._messages._queued_messages
, and if that's set, add a HX-Trigger
response header to the response, and this could cause the client to make a request back to the server to collect the messages.
https://github.com/django/django/blob/main/django/contrib/messages/middleware.py#L22
https://github.com/django/django/blob/main/django/contrib/messages/storage/base.py#L149
Might also be possible to do it this way:
https://docs.djangoproject.com/en/dev/ref/contrib/messages/#expiration-of-messages
I don't know what I'm talking about. I just would like Django messages to appear, and if django-htmx can assist this in a nice way...
In my project I've created a management command based on https://github.com/adamchainz/django-htmx/blob/main/example/download_htmx.py.
Would it be desirable to include a management command directly in this project for this purpose?
I find myself frequently using a htmx_only decorator in my projects for requests that do not push to history on the client-side (hx-push-url="false"). While I am not a strict adherent to HATEOAS principles, such a decorator still aligns with them imo.
Regarding what should be done when a request is not an htmx one, I think that returning an HTTP 400 or 412 (I currently use 400) would be appropriate.
If a htmx_only decorator would be a useful addition to django-htmx, I am willing to submit a pull request.
https://htmx.org/headers/x-hx-trigger/
I'm imagining something similar to Django's patch_cache_control
that allows adding events to a response:
response = ...
trigger_client_event(name="confetti", params={"amount": 10000}, after='settle')
the frequent following pattern could be embedded in a mixin à la django :
template_name = "survey/question_list.html"
def get_template_name(self, request):
if request.htmx:
return "survey/question_list_partial.html"
proposed mixin :
class HTMXPartialTemplateMixin:
"""
A template mixin that appends _partial to the template name in case of
a partial request via HTMX.
this default behaviour can be overridden by setting the
partial_template_name class attribute.
"""
partial_template_name = None
def get_template_name(self, request, **kwargs):
if not request.htmx:
return self.template_name
if self.partial_template_name:
return self.partial_template_name
else :
return self.template_name.replace(".html", "_partial.html")
then used like so :
class Questionlist(ListView, HTMXPartialTemplateMixin):
template_name = "survey/question_list.html"
def get(self, request):
template_name = self.get_template_name(request)
This idea is credited to @malmiteria, it makes the ol' if request.htmx -> partial template more DRY. This mixin is far from perfect but it could be a start
current_url
returns the full URL:
>>> request.htmx.current_url
'https://www.pythonmorsel.com/some-page/
I'd like a way to access just the non-domain part of this URL (I'm using it for a ?next=
login redirect).
>>> request.htmx.relative_current_url
'/some-page/
I imagine something like this might work.
@cached_property
def relative_current_url(self) -> str | None:
url = self.current_url
if url:
urlunparse(urlparse(url)._r(scheme='', netloc=''))
return url
if possible can you guys create a video tutorial using a django app with htmx? the django app can be new meaning you create a new django project and then use htmx for the frontend, or refactor a django app using htmx for the frontend. I learn best by watching, reading, and practicing.
Hello,
I don't have a credit card and I can't pay for your book, which looks really good. I wanted to buy it to support the project, but would it be possible to pay you by another way? Paypal/Mollie/crypto/.... and if possible receive the book 😄
Thank you in advance
No response
No response
No response
The debug
script is super useful, however, since I don't know the internals of htmx-django
and how exactly is debug
on/of
inferred, I'm wondering how secure it is.
Currently this is what I have in my base.html
:
<head>
{% django_htmx_script %}
<script src="{% static 'javascripts/htmx/htmx.min.js' %}" defer></script>
<script src="{% static 'javascripts/hyperscript/hyperscript.min.js' %}"></script>
</head>
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}' hx-ext="debug">...</body>
Is this safe? the documentation does not state hx-ext="debug"
should be only be included if {{ debug }}
is on
. Where does that check happen?
Hi,
It might be interesting to use DjangoJSONEncoder when dumping a dict in trigger_client_event.
django-htmx/src/django_htmx/http.py
Line 63 in 825e349
response[header] = json.dumps(data, cls=DjangoJSONEncoder)
It would be nice to have some added ways to send the header Hx-Retarget and hx-reswap
Maybe analog of trigger_client_event having a re_trigger_client_event
3.10
4.1
1.13.0
on the context processor:
def custom_context(request):
return {
"OUTERHTML_W_DURATION": f"outerHTML swap:{settings.DOM_SWAP_DURATION}",
}
it is properly registered in the settings, full page responses compile the value properly
on the template:
hx-swap="{{OUTERHTML_W_DURATION}}"
Hello,
I'm using the project and have identified some (IMO) nice additions around mixins and views.
HtmxTemplateResponseMixin
based on TemplateResponseMixin
. This allows people to pass a htmx_template_name
value in class based views.https://github.com/Tiny-Tiny-App/django-htmx/blob/htmx-views-and-mixins/src/django_htmx/mixins.py
HtmxFormView
that implements the HtmxTemplateResponseMixin
. This allows people to define a template to be used as the return value.https://github.com/Tiny-Tiny-App/django-htmx/blob/htmx-views-and-mixins/src/django_htmx/views.py
Are these additions that fall in line with the project goals?
I'm in the process of writing tests but dont have a clear idea of how y'all are setting up the testing infrastructure.
Could you be so kind and add information to the readme (well here as well) about how to run and add tests to this repo?
requirements.txt
from the example app are missing django-htmx
dependency.
I was curios to try this package as I wanted to dig into HTMX, but I could not get the example project up and running. A little showstopper in the requirements:
But now I am stuck with these errors:
File "..\venv\lib\site-packages\django\utils\module_loading.py", line 20, in import_string
return getattr(module, class_name)
AttributeError: module 'django_htmx' has no attribute 'HtmxMiddleware'File "..\venv\lib\site-packages\django\utils\module_loading.py", line 22, in import_string
raise ImportError('Module "%s" does not define a "%s" attribute/class' % (
ImportError: Module "django_htmx" does not define a "HtmxMiddleware" attribute/class
Also, is there a particular reason this would not work with Django 3.1 but only 3.0.12?
New in 1.2.0: https://htmx.org/posts/2021-2-13-htmx-1.2.0-is-released/
Hello, firstly I want to say thank you because I find this project very useful! I was finding it difficult to debug some errors in a project that I'm working on, so I subclassed the middleware to return errors to the frontend like this:
import traceback
from django.conf import settings
from django.http import HttpResponse
from django_htmx.middleware import HtmxMiddleware
class HtmxDebugMiddleware(HtmxMiddleware):
def process_exception(self, request, exception):
if request.htmx and settings.DEBUG:
content = (
"<h1>Django HTMX Error</h1><b>%s</b>"
"<h3>Traceback</h3><textarea rows=10>%s</textarea>"
) % (
exception,
traceback.format_exc(),
)
return HttpResponse(content, status=200)
return None
Here is an example of what the solution above produces when raise RuntimeError("Something bad happened on the backend!")
is encountered:
Would it be desirable to include something similar in this project?
I would suggest a better readme by adding examples (use case) and snippets, to make it more beginner friendly.
Hi! Thanks for all the work towards this great project.
In CORS contexts, headers need to be explicitly allowed for requests, and exposed for responses via the Access-Control-Allow-Headers
and Access-Control-Expose-Headers
headers, respectively. It might be handy if this library's middleware could take care of that through a simple boolean setting.
Also, are you aware of a new beta feature that allows discussions in a separate tab? https://docs.github.com/pt/free-pro-team@latest/discussions I think questions like mine would be better off in discussions to avoid polluting issues
3.9.5
3.2.7
1.3.0
When submitting a post request in a form I get this nested form inside a form outcome:
{% extends "base.html" %}
{% load widget_tweaks %}
{% block content %}
<section class="bg-gradient-to-b from-gray-50 to-white">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="pt-32 pb-12 md:pt-40 md:pb-20">
<!-- Page header -->
<div class="max-w-3xl mx-auto text-center pb-12 md:pb-20">
<h1 class="h1">Welcome. We exist to make entrepreneurism easier.</h1>
</div>
<!-- Form -->
<div class="max-w-sm mx-auto">
{% include "social_account/social_login.html" %}
<div class="flex items-center my-6">
<div class="border-t border-gray-300 flex-grow mr-3" aria-hidden="true"></div>
<div class="text-gray-600">or</div>
<div class="border-t border-gray-300 flex-grow ml-3" aria-hidden="true"></div>
</div>
<form method="POST" hx-post="{% url 'core:signup'%}" hx-swap="innerHTML">
{% csrf_token %}
{% for field in form %}
<div class="flex flex-wrap -mx-3 mb-4">
<div class="w-full px-3">
<label class="block text-gray-800 text-sm font-medium mb-1">
{{field.label}}<span class="text-red-600 ml-1">*</span></label>
{% if field.errors %}
{% render_field field class="form-input-danger w-full text-gray-800" placeholder=field.field.widget.attrs.placeholder %}
{% else %}
{% render_field field class="form-input w-full text-gray-800" placeholder=field.field.widget.attrs.placeholder %}
{% endif %}
{% for error in field.errors %}
{% #alerts_form %}
{{error}}
{% /alerts_form %}
{% endfor %}
</div>
</div>
{% endfor %}
<div class="text-sm text-gray-500 text-center mt-3">
By creating an account, you agree to the <a class="underline" href="#0">Terms of Service</a>, and our <a class="underline" href="#0">Privacy Policy</a>.
</div>
<div class="flex flex-wrap -mx-3 mt-6">
<div class="w-full px-3">
<button class="btn text-white bg-blue-600 hover:bg-blue-700 w-full">
Sign up</button>
</div>
</div>
</form>
<div class="text-gray-600 text-center mt-6">
<a class="text-blue-600 hover:underline transition duration-150 ease-in-out" href="{% url 'core:login' %}">Already using Simple?</a>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
I tried to add hx-swap="outerHTML"
and hx-swap="innerHTML"
, yet none of them seem to help.
What am I doing wrong?
After @adamchainz reply I wanted to leave an example behind for others:
class IndexView( TemplateView):
template_name = "app/index.html"
def get(self, request, *args, **kwargs):
try:
search = request.GET.get("search")
orders = Order.objects.filter(Q(description__icontains = search) | Q(device__name__icontains = search))
except:
orders = Order.objects.all()
page_num = request.GET.get("page", "1")
page = Paginator(object_list = orders, per_page = 5).get_page(page_num)
if request.htmx:
base_template = "app/_partial.html"
else:
base_template = "app/index.html"
part_template = "app/partial-rendering.html"
return render(request, part_template, {"base_template": base_template, "page": page,},)
The html code is fairly easy:
<section>
search:
<input class="form-control"
type="text"
name="search"
placeholder="search for orders..."
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-get="/"
hx-push-url="true"
hx-trigger="keyup changed delay:500ms"
hx-target="#main"
hx-indicator=".htmx-indicator">
</section>
<main role="main" id="main">
{% include "app/orders_table.html" %}
</main>
hope that helps someone :)
git
In the readme file there is a hint how to use the templatetag:
For Django Templates, load and use the template tag:
{% load django_htmx %}
{% django_htmx_script %}
It's not clear: do I need to include {% django_htmx_script %}
too in every (sub)template where I want to use htmx? Or is it ok to do it once in the base template?
For {{ django_htmx_script() }}
you make it clearer, it's only needed in the base template.
Maybe you could improve that, for beginners...
I really like the solution of #86, but I think my users will still want to see something in the page if an error occurs in the backend. I am thinking of an implementation I've done with jquery and bootstrap modal where the edit dialog appears - if there is a simple form error, they see the errors in the form and the modal doesn't disappear. Currently, if there is an 500-error, the form just disappears in production and they know something is wrong, but not what. I wish I could do better but I am struggling to get the 20k lines of PL/SQL into Python/Django Models/SQL without losing the performance (pity me).
If I were to rewrite this application with HTMX (which I would love to have time to do), how would I do better and show them something in the UI like "System error occurred"?
Obviously, each call can use try/exception block to catch errors and return them, but maybe there should be a Django setting for an error template in production, or maybe I can handle this entirely with some sort of JavaScript handler - but if I do that, am I missing some of the advantages of HTMX?
No response
No response
No response
This is more an idea than an issue. Sorry if there's a better place to share.
I recently added HTMX to a website that wasn't using it before. It was a fairly typical CRUD-like app and after about the third page, I realized the transformations I was making (e.g. adding hx-target and hx-select on a bunch of elements) were fairly mechanical. I then wrote a function as a middleware that made the transformations (mostly) automatically.
The middleware worked by parsing the HTML response, looking for form tags, and adding the hx-target/hx-select fields when an id attribute was present on the tag. I typically would replace the outer HTML to get a nice interactive result. Does that make sense? The overall goal was to leave the templates as-is and use middleware to automatically add the "hx-" tag attributes.
I know this pattern won't be universal but I wanted to share here and ask for your thoughts. If you survey your use of HTMX in Django templates, are the changes mostly mechanical? And could we automate that?
Hi Adam,
Thank you for maintaining this library, it is very practical to have almost all HTMX shortcuts so nicely integrated in Django.
I miss one though: did you ever considered adding a shortcut for hx-vals ? It could be pretty useful.
The hx-vals attribute allows you to add to the parameters that will be submitted with an AJAX request.
I am accessing those values when doing stuff like that: https://github.com/spookylukey/django-htmx-patterns/blob/master/inline_partials.rst#block-selection-in-the-template
Thank you very much.
Regards.
;-)
In a project I'm working on we logout priviliged users after some time. This has the downside of returning a HttpResponseRedirect
when issuing a htmx request, ie. when a user tries to use an already open browser tab the next day.
For now we have solved the problem by writing the following middleware:
class HtmxRedirectMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if request.htmx and isinstance(response, HttpResponseRedirect):
# Set the HX-Redirect to the current location to imitate a reload
response["HX-Redirect"] = response["Location"]
# htmx only accepts 200's
response.status_code = 200
return response
This tells htmx to do a complete reload of the page leading to a redirect to the login page.
I think that the above approach might be a bit too generic - do we want to issue a redirect every time? For now it serves us fine since we are evaluating htmx in a small portion of our project.
The question is whether django-htmx should offer something similar?
Is it possible mixing HTMX using django-htmx for a modal create/update dialog htmx-modal-dialog-example without a page refresh?
I would appreciate if you throw me a bone:
<button
id="showButton"
hx-get="/create"
hx-target="#modals-here"
class="uk-button uk-button-primary"
_="on htmx:afterOnLoad wait 10ms then add .uk-open to #modal">Open Modal
</button>
<div id="modals-here"></div>
simple form / createview / urls.py entry:
class ProductForm(ModelForm):
class Meta:
model = Product
fields = ("description", "price",)
class CreateProductView(TemplateView):
def get(self, request, *args, **kwargs):
return render(request, "app/product_create.html", {'form': ProductForm})
path("create/", views.CreateProductView.as_view(), name = 'create'),
What I did now is, that i used the DRF API to POST new products into the database, which is obviously not recognized by htmx (but this way via AJAX I can avoid a reload). I also feel kind of guilty, because I had to use a second view (I wanted to use my normal view, but there is no way to send a "name" attribute via hx-get in a button to the view).
So ... two questions and a request in the end for this cool little extension:
3.10
3.2.7
1.6.0
Firstly: thank-you for your hard work on the package and the documentation.
I have a bit of a problem with the hx-headers / CSRF example.
I've set DEBUG to True and use static locally boilerplate & installed htmx using the script - everything's in place and working. Css,
However, when I fill in the form, the form GETs from http://127.0.0.1:8080/csrf-demo/?number=5. It does not do a POST to /csrf-demo/checker/ as I would expect it to.
And I get a [Error] SyntaxError: Unexpected identifier 'find' (anonymous function) (htmx.js:1)
I'm sure I'll figure it out eventually, but if you have any suggestions I'd be most grateful.
3.10.6
4.1
1.13.0
Below is the implementation for context:
def current_url_abs_path(self) -> str | None:
url = self.current_url
if url is not None:
split = urlsplit(url)
if (
split.scheme == self.request.scheme
and split.netloc == self.request.get_host()
):
url = urlunsplit(split._replace(scheme="", netloc=""))
else:
url = None
return url
Problem:
When the application server is behind a proxy like Nginx it can happen that condition split.scheme == self.request.scheme
is False (request.scheme has value http while split.scheme has value https).
I'm not sure what's the purpose of these conditions checks. Eventually, I would suggest to remove these checks.
Building on #222, it would be intersting to let user declare a subclass of HtmxDetail
with helpers and have a setting variable pointing out to the location:
HTMX_DETAIL_CLASS = "here.is.my.HtmxDetailSubClass"
Currently, trigger_client_event
returns None after adding the custom event name and params to the response header.
def view(response):
...
response = render(request, self.template_name , context=context)
trigger_client_event(
response=response,
name="showMessage",
params={
"value": message
}
)
return response
making it return the modified response would imo allow for a more elegant view code (or even maybe add multiple events) :
def view(response):
...
response = render(request, self.template_name , context=context)
return trigger_client_event(
response=response,
name="showMessage",
params={
"value": message
}
)
This needs either JS or hyperscript to handle the error events (sendError
, responseError
) from htmx.
from the event-header extension: https://htmx.org/extensions/event-header/
Thanks for this app and demo code!
I configured and ran the example app per the instructions, but get CSRF errors when trying to use the Middleware Tester page buttons & input. Log output is the following:
Forbidden (CSRF token missing or incorrect.): /middleware-tester/table/
[16/Feb/2021 01:59:07] "PUT /middleware-tester/table/ HTTP/1.1" 403 2513
This error goes away if I add the CSRF token to the test buttons and input in middleware-tester.html
, e.g.:
<button id="basic-button"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-put="/middleware-tester/table/">
Basic button
</button>
I'm running on Ubuntu. I get the same CSRF error whether using Firefox, Chrome or Brave.
A few of us at PyCon this year got together and brainstormed a new Web Stack that we are calling PyHAT (Python, htmx, ASGI, TailwindCSS). The first thing we set out to do is create awesome-python-htmx; a collection of active tools/libraries/projects in that space.
Your project seems like an obvious thing to include, so I did. I'd appreciate your feedback if you have any on it's inclusion.
In addition to that, if you could also participate in PyHAT-stack/awesome-python-htmx#1 that would be greatly appreciated!
I have been using htmx
for a while and developed a pattern in using
href="#" hx-get="some_url" hx-swap="innerHTML"
hx-target="#content-wrapper" hx-select="#content"
hx-push-url="true"
I used a wrapper for #content
due to this problem of using outerHTML
to swap #content
directly.
The advantage of this approach is that
some_url
is requested directly (non-htmx), the entire page will be displayed.some_url
is requested through htmx, the content outside of #content-wrapper
will be ignored, so the page will not be refreshed and flick.This overall works well but I am wondering if the backend can be more clever in handling hx-target
. Namely, if the request.htmx
is True
and there is hx-target
, only the target portion will be returned to the frontend, which could, at least in theory, reduce the network traffic and burden of frontend.
This could be done explictly as follows:
entire_page.html
defined as{% extends "base.html" %}
{% include "partial.html"%}
htmx
request as followsif request.htmx:
# also test hx-target if needed
return render('partial.html')
return render('entire_page.html')
This can be done but it is difficult to maintain since it requires the frontend and backend to work together (e.g. change of hx-target
selector, change of partial.html
). I am therefore wondering if the same can be achieved at the middleware level through django-htmx
.
The middleware will post-process HttpResponse
to remove content outside of hx-target
. Things can be a little complicated with
hx-select
target. The middleware could ignore hx-target
that is not #id
and pass the more complicated cases to the frontend.hx-swap-oob
, not sure how to do this, but again we can pass pages with hx-swap-oob
to the frontend.Does this sound like a valid feature to implement in django-htmx
? I suppose that the biggest problem could be that the middleware is difficult to implement (parsing HttpResponse
) and introduces bugs that are difficult to debug (frontend not receiving content as expected).
When one uses a single URL for both HTMX and non htmx responses, it can confuse the browser in to caching HTML fragments for a URL rather than the whole page when that URL has been requested on load, and then subsequently by HTMX. The fix suggested over here is to use the HTTP Vary
header.
As such I have a small custom middleware, which I wondered about if it would make sense to combine with the main django-htmx
, probably with a setting to control it.
My current extra middleware:
def htmx_vary_header_middleware(get_response):
"""Middleware that adds `HX-Request` to the vary headers to prevent browser caching
html fragments when a URL can return full pages, or HTMX fragments."""
def middleware(request):
response = get_response(request)
patch_vary_headers(response, ("HX-Request",))
return response
Happy to make a PR if there is any interest?
I wanted to hear if there is any interest in adding the X-CSRFToken to every HTMX request by grabbing the htmx:configRequest
event?
I've had quite a good success by including the following in my base templates:
<script>
// Make sure we have csrf_token in HTMX requests
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
Including this in django-htmx by either modifying django-htmx.js (and removing the non-debug guard in jinja.py) could be one way of doing it. Another could be a seperate {% htmx_csrf_header %}
template tag.
Any thoughts?
https://htmx.org/docs/#polling
If you want to stop polling from a server response you can respond with the HTTP response code 286 and the element will cancel the polling.
This is a non-standard code, not found in python's http.HTTPStatus
, so it would be nice to add some way to reference it without hardcoding the number.
Hello, maybe you could add a htmx decorator which renders different template if using TemplateResponse
in the view ?
Here's an example, from Luke's repo:
https://gitlab.com/learnscripture/learnscripture.net/-/blob/master/learnscripture/decorators.py#L80
Thanks!
Okay, the title is a bit strange, bear with me for a second while I explain.
When I was figuring out how htmx and django played together, I stumbled upon the fact that if you you hx-push-url="true"
and that url is a view with a partial template (such as would be used for hx-get), it rendered only that partial. At first I thought, "oh, right. that won't work." So your solution here with checking if a request is request.htmx
or not solves that problem nicely.
But then I realized... it could actually be extremely useful for development and testing. When I rendered just that one form I was testing, outside of the context of the rest of the page, it was... really nice. I could hone in on just the component that I was testing, coming from that view. In the case of a modal, the rest of the page is pretty irrelevant when I want to test and develop just that modal in isolation.
So what I started doing was, I had a base.html
template that looked like this:
<!DOCTYPE html>
<html>
<head>
<title>Stocker!</title>
<script src="https://unpkg.com/[email protected]" integrity="sha384-t37OW0DbqgL50XZW+Tl8TLchxsPoxIJ7NQ/l4aSZIXZVJQAhyQvvkWZgL/SiY/jD" crossorigin="anonymous"></script>
<script src="https://unpkg.com/[email protected]"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css">
</head>
{% block base %}
{% endblock %}
</html>
and a base_body.html
template that actually contained my 'base layout', my navbar, my structural stuff.
My "pages", like the home page, extend base_body.html
and are fully part of the layout.
My "components", like a modal, extend "base.html" so that they get the relevant scripts and css etc, but are rendered in isolation.
So my thought is, can I have both this "render just this component for testing and debugging and stuff" request path, and the dual "partial vs complete" path as demonstrated in your demo? Is that feasible? (More importantly, do I really want it? When I demo it to colleagues, they think it's potentially a really cool feature, but maybe it's silly.) Could there be some sort of DEBUG
related flag that allows you to render the partial in a request or in a test?
Thanks for hearing my rambling. Hope some of that made sense.
No response
No response
No response
This is more a question more than anything, maybe it’s worth opening a Discussions tab here?
Scenario:
Logged in. Two tabs open. One has the form on it. On the second, user logs out, and the link back in. Tab 1’s CSRF token is now invalid. Now user goes to tab 1 and submits the form.
How do I handle this with HTMX? Right now I’m returning the form and replacing it with hx-swap
, but when the above scenario occurs - the form gets swapped with the whole layout and the CSRF error view that handles this scenario.
So given that the form view is not eve called and it's not another “form invalid” kind of error, what’s the most HTMXy way to handle this?
In a project I'm working on, I created two simple helpers I use in combination with this package, so I was thinking about making a pr to add these as simple utils. Do you guys think it will be useful ?
from functools import wraps
from django.shortcuts import render
class HtmxView:
success_url = "."
@property
def htmx_template(self) -> str:
raise NotImplemented
@property
def htmx_partial(self) -> str:
raise NotImplemented
@property
def template_name(self) -> str:
return self.htmx_partial if self.request.htmx else self.htmx_template # noqa
def htmx_view(htmx_template: str, htmx_partial: str):
def inner(view):
@wraps(view)
def func(request, *args, **kwargs):
context: dict = view(request, *args, **kwargs)
template = htmx_partial if request.htmx else htmx_template
return render(request, template, context)
return func
return inner
# Examples
class ContactView(HtmxView, FormView):
form_class = ContactForm
htmx_partial = "partials/contact_form.html"
htmx_template = "pages/contact.html"
@htmx_view(htmx_template="pages/contact.html", htmx_partial="partials/contact_form.html")
def contact(request):
return {"form": ContactForm()}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.