Unicorn – A full-stack web framework for Django
django-unicorn.com
django-unicorn.com
htmx and alpine.js are great libraries to provide interactivity to your HTML. Both of those libraries are generalized front-end framework that you could use with any server-side framework (or just regular HTML). They are both well-supported, battle-tested, and answers to how they work are probably Google-able (or on Stackoverflow).
Unicorn isn’t in the same league as either htmx or alpine.js. But, the benefit of Unicorn is that it is tightly integrated with Django and it should “feel” like an extension of the core Django experience. For example:
* redirecting from an action uses the Django redirect shortcut
* validation uses Django forms
* Django Models are tightly integrated
* Django messages “just work” the way you would expect them to
* you won’t have to create extra URLs/views for AJAX calls to send back HTML because Unicorn handles all of that for you
I still don't understand what they mean when they say "HTMX is HATEOAS": it's not parsing the response to decide things based on relations, it's not following any links, you can still have out-of-band info if you want...it's just substituting a string given by the server on the DOM.
A JSON API can be as hypermedia as HTML (I remember HAL-FORMS and Collection+JSON). A web app that consumes such an API is doing "HATEOAS" even if it's using React.
I really like the HTMX project (that and Unpoly are a godsend) but sometimes it sounds more grandiose than it is: just the regular web doing what it always did, except you program the interactive fetching/swapping of pages/fragments in HTML instead of JS, i.e. AJAX with HTML attributes.
REST was ok for the read-side of things, but for writing I find RPC/commands to be better than PUT/PATCH. Combine that with the lack of framework for HATEOAS made full REST APIs cumbersome at the time, though things may be different now.
htmx is a very small and very predictable library. The underlying pattern is well established among many libraries and probably countless similar implementations.
I have implemented something like htmx several times before htmx came out, and I assume many others have too. I just didn't take the time to extract a clean, generalized and comprehensive library.
This is the uncanny valley for me, it's neither the old school web or "SPA land" (for a lack of a better term). In the todo example, I write some garbage and press "Add", there is absolutely 0 feedback anything happened. I then press it again. About 100ms later, the first thing I typed appeared, then slightly later it got replaced with nothing.
I have no idea how I'd fix that in this framework, there's too much magic for me to figure out where I'd insert a "fix" for this. I'd probably start writing my own javascript to disable the button while it's submitting (which isn't great, but better than today), at which point the "magic" is lost.
I never expected Unicorn to completely replace larger SPA frameworks, but I have found it solves for most of the use cases I need for my sites.
Thanks for checking it out -- all PRs are greatly appreciated to add new features or fix bugs!
Laravel Livewire (https://livewire.laravel.com)
HTMX (https://htmx.org)
Hotwire (https://hotwired.dev/)
Phoenix LiveView (https://github.com/phoenixframework/phoenix_live_view)
Last year I had a month free and I had a go at building something for Django in this area, with a bunch of interesting ideas - built on Alpine.js, resumable server side component state, inline component templates. But sadly time is limited and I just can't spend the time needed to push it further. One day I may be able to pivot back to it, but would be very happy for someone to take some of these ideas and run with them - https://www.tetraframework.com/
What I really want to see is a modern asset + front end build solution for Django. It would enable more of these sorts of projects. Thats what needs to be built into Django.
My opinion: They should go the Phoenix Live View-route: adding a small websocket js layer, that permits reactivity while deferring as much logic to the backend as possible.
See also Rails, which did choose a battery quite early on: prototype.js. Well, that was a wrong decision, so they changed it to jQuery (which is now also deprecated; no idea what it supports nowadays) and also dropped their RJS templating language. Lots of breakage and churn on every major release for us poor sods who made use of such features.
Migrating a small website from one to the other is trivial.
Migrating a large enough website was for my team a multi-month affair involving hours-long debugging sessions, opening tickets in multiple Github projects and contributing to the projects.
Decoupling different software components is a good thing.
A LOT of companies ?
Certainly AngularJS was more contemporary with Backbone and was actually both relatively pleasant to use in its era and long outpaced now.
It's important to note that most users do not care whether a page refreshes or not. That's mostly the developers - being used to SPA's and frameworks. You can build basic requirements very rapidly with Django as-is.
That’s the problem - it shouldn’t be.
Would be an awesome pattern to demonstrate, but doesn't have to be built in..
Something that is nagging me though is the (still) rather incomplete take on client-side reactivity. Alpine.js is by-and-large addressing this in a pleasantly minimalistic way, but for this new take to become a defacto standard of lean and mean modern web development I feel there should be uniform semantics and integration that spans the different server-side stacks. This way code and knowledge would be reusable and not tied to a specific language/web platform.
Name collision is unavoidable and one of the many wrong battles to fight for, IMO.
pip install django-unicorn
and used with from django_unicorn.components import UnicornView
like any other python module used in a Django app, I'd say that it brings the full stack inside Django, much like its counterparts for Laravel, Phoenix and Rails. What was only backend plus server side generated pages is also Javascript now, written inside the backend without even having to know Javascript.ST was easily the most pleasant experience I've ever had developing front end using a Python backend.
https://www.django-unicorn.com/examples/validation
This does a POST each time, albeit automatically on typing. It still means a lag for a kind of validation that could have been done client side.
If you can accept that lag, the tradeoff is that you only have to write the validation logic once, in one language. Furthermore, if your validation includes something like "check that this username isn't already registered" that requires server-side logic, you're stuck with that POST request and lag anyway.
class TodoView(UnicornView):
create a model? class UnicornView(TemplateView)
and from django.views.generic.base import TemplateView
Is this Django magic a Flasker doesn't get?These days I prefer to build my back end applications with nodejs, TypeScript and plain SQL (no ORM) talking to Postgres.
I like Django but it pissed me off no end that it's called "batteries included", except that the very first thing you need to do with any Django project is going and find some batteries for the user signup auth flow. That's not batteries included, and its not something you should need to figure out for yourself in a batteries included framework. It's time consuming, complex and error prone and should be built in.
Anyhow as I say, I've prefer nodejs though I still do use Python for lots of stuff.
The fact that the Django project and you have different preferences and consider different things essential is not a failure on their end. The fact that this "pisses you off" seems to indicate that you could channel your passion into more productive paths.
There's a reason why only admin views are kind of built in and if you want you can expose admin to the end user and it supports the entire Auth flow out of the box.
The fact that there are many possible add ins to solve this doesn't address the fact that Django does not include core functionality for web applications.
Asking because I've had some experience with nest.js and even though it's fun it often feels hackish and a bit messy even when solving standard issues like authorization that's not a simple app wide RBAC.
I can say that nodejs and TypeScript and pure SQL is so simple and straightforward that I seem to need almost nothing in terms of "framework". I just write endpoints with a query behind them.
On reflection I spent alot of development time hacking around in Django models/forms and the ORM and really almost none of that is needed if you just write straight SQL with Postgres. It's just unnecessary complexity - once you cut all that guff out then things start to become REALLY simple. Request/auth/query/response.
I put auth into a separate web application which gets called by Caddy (or you coudl use Nginx) as an auth subrequest. This makes auth extremely easy, and gives a very powerful decoupling and separation of concerns.
For many years I have thought, finally, that's the last time I need to write a user signup/forgot password/signin flow, but every project still seems to need it written, so I do that myself.
This approach of super simple, just talking to Postgres also would work well with Python but I have come to really like TypeScript more than Python. The latest Python projects I wrote were pretty much Starlette with asynpg talking to Postgres and no ORM or other fluff - that's a pretty nice combination, and asyncpg is the fastest Postgres driver for Python by a country mile which is also nice.
If I wanted RBAC then I would intercept all my SQL queries and wrap them in Postgres RBAC environment variables that implement the Postgres constraints. I've done this before with Django, it worked pretty well, but I think it would be nicer and cleaner in a system without ORM or database abstraction of any form.
It's typically not practical to solve "auth flows" in a centralized way -- needs are so different for different projects. There are tons of third party modules you can just plug in...
It's 2023, people log in with e-mail addresses, and even if they log in with a username, make it case insensitive ffs
The very first thing I have to do with each project is completely rebuild the user system, and if you wait until later then it's too late and it's way more difficult to do (according to the docs themselves)
The moment you install Django, you have to add all the auth stuff to your todo list. If you're not a Django expert then its easily hours or days pointless work.
Pretty frustrating to instantly be given the large and for some people intimidating problem of implement signup/signin/forgot password/reset password and do it all properly, reliably and securely, even whilst Django smugly asserts that it's "batteries included".
You have to head off and find which auth plug in system to use, work out what is still maintained, which provides the features you need and then the task of integrating it with whatever front end you need to present to the user. All this you need to do if you are new to Django.
It's a huge gap in the Django offering, and makes Django look pretty out of date.
Django should come with a built in user flow that allows signup/signin/forgot password/reset password as well as related emails, and it should come with support for json web token and cookie session, plus example UI code for React, VueJS, plain HTML and maybe some of the other common JavaScript front ends too, as well as APIs for other front ends to use.
Why they don't provide this is hard to understand. It's just instant makework for developers.
Either this or drop the "batteries included" thing.