* Home :PROPERTIES: :ONE: one-custom-default-home :CUSTOM_ID: / :TITLE: :DESCRIPTION: Framework for creating Realtime SPAs using HTML over the Wire technology. :END: ** What is Django LiveView? Django LiveView is a framework for creating Realtime SPAs using HTML over the Wire technology. It is inspired by Phoenix LiveView and it is built on top of Django Channels. It allows you to create interactive web applications using only HTML, CSS and Python. JavaScript ONLY is used to capture events, send and receive strings over a WebSockets channel. ** What are your superpowers? - Create SPAs without using APIs. - Uses Django's template system to render the frontend (Without JavaScript). - The logic is not split between the backend and the frontend, it all stays in Python. - You can still use all of Django's native tools, such as its ORM, forms, plugins, etc. - Everything is asynchronous by default. - Don't learn anything new. If you know Python, you know how to use Django LiveView. - All in real time. Now you can create SPAs without using APIs, without JavaScript, and without learning anything new. If you know Python, you know how to use Django LiveView. Are you ready to create your first Realtime SPA? Let's go to the [[#/docs/quickstart/][Quickstart]]. * Quickstart :PROPERTIES: :ONE: one-custom-default-doc :CUSTOM_ID: /docs/quickstart/ :TITLE: Quickstart :DESCRIPTION: Get started with Django LiveView the easy way. :END: All the steps are applied in a [[https://github.com/Django-LiveView/minimal-template][minimalist template]]. ** 1. Install Django Install Django, create a project and an app. ** 2. Install LiveView Install django-liveview with ~pip~. #+BEGIN_SRC sh pip install django-liveview #+END_SRC ** 3. Modify the configuration Add ~liveview~ to your installed ~INSTALLED_APPS~. #+BEGIN_SRC python INSTALLED_APPS = [ "daphne", "channels", "liveview", ] #+END_SRC Then indicate in which previously created App you want to implement LiveView. #+BEGIN_SRC python LIVEVIEW_APPS = ["website"] #+END_SRC ** 4. Migration Execute the migrations so that the LiveView tables are generated. #+BEGIN_SRC python python manage.py migrate #+END_SRC ** 5. ASGI Modify the ASGI file, ~asgi.py~ to add the LiveView routing. In this example it is assumed that settings.py is inside core, in your case it may be different. #+BEGIN_SRC python import os import django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") django.setup() from channels.auth import AuthMiddlewareStack from django.core.asgi import get_asgi_application from channels.security.websocket import AllowedHostsOriginValidator from channels.routing import ProtocolTypeRouter, URLRouter from django.urls import re_path from liveview.consumers import LiveViewConsumer application = ProtocolTypeRouter( { # Django's ASGI application to handle traditional HTTP requests "http": get_asgi_application(), # WebSocket handler "websocket": AuthMiddlewareStack( AllowedHostsOriginValidator( URLRouter([re_path(r"^ws/liveview/$", LiveViewConsumer.as_asgi())]) ) ), } ) #+END_SRC ** 6. Create your first Action Place where the functions and logic of the business logic are stored. We will start by creating an action to generate a random number and print it. Create inside your App a folder called ~actions~, here will go all the actions for each page. Now we will create inside the folder a file named ~home.py~. #+BEGIN_SRC python # my-app/actions/home.py from liveview.context_processors import get_global_context from core import settings from liveview.utils import ( get_html, update_active_nav, enable_lang, loading, ) from channels.db import database_sync_to_async from django.templatetags.static import static from django.urls import reverse from django.utils.translation import gettext as _ from random import randint template = "pages/home.html" # Database # Functions async def get_context(consumer=None): context = get_global_context(consumer=consumer) # Update context context.update( { "url": settings.DOMAIN_URL + reverse("home"), "title": _("Home") + " | Home", "meta": { "description": _("Home page of the website"), "image": f"{settings.DOMAIN_URL}{static('img/seo/og-image.jpg')}", }, "active_nav": "home", "page": template, } ) return context @enable_lang @loading async def send_page(consumer, client_data, lang=None): # Nav await update_active_nav(consumer, "home") # Main my_context = await get_context(consumer=consumer) html = await get_html(template, my_context) data = { "action": client_data["action"], "selector": "#main", "html": html, } data.update(my_context) await consumer.send_html(data) async def random_number(consumer, client_data, lang=None): my_context = await get_context(consumer=consumer) data = { "action": client_data["action"], "selector": "#output-random-number", "html": randint(0, 10), } data.update(my_context) await consumer.send_html(data) #+END_SRC There are several points in the above code to keep in mind. - ~template~ is the name of the template that will be rendered. - ~get_context()~ is a function that returns a dictionary with the context of the page. - ~send_page()~ is the function that will be executed when the page is loaded. - ~random_number()~ is the function that will be executed when the button is clicked. ** 7. Create the base template Now we will create the base template, which will be the one that will be rendered when the page is loaded. Create a folder called ~templates~, or use your template folder, inside your App and inside it create another folder called ~layouts~. Now create a file called ~base.html~. #+BEGIN_SRC html {# my-app/templates/layouts/base.html #} {% load static i18n %} {% get_current_language as CURRENT_LANGUAGE %}