{"id":25534338,"url":"https://github.com/diegojromerolopez/django-ws-include","last_synced_at":"2025-11-11T20:21:21.250Z","repository":{"id":45024277,"uuid":"445608749","full_name":"diegojromerolopez/django-ws-include","owner":"diegojromerolopez","description":"Include your templates asynchronously and load their contents using websockets","archived":false,"fork":false,"pushed_at":"2022-01-16T17:32:00.000Z","size":54,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-22T13:47:38.308Z","etag":null,"topics":["async-loading","django","template-tag","websockets"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diegojromerolopez.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-07T17:57:25.000Z","updated_at":"2022-02-01T09:15:09.000Z","dependencies_parsed_at":"2022-08-28T07:40:31.345Z","dependency_job_id":null,"html_url":"https://github.com/diegojromerolopez/django-ws-include","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fdjango-ws-include","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fdjango-ws-include/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fdjango-ws-include/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fdjango-ws-include/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diegojromerolopez","download_url":"https://codeload.github.com/diegojromerolopez/django-ws-include/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248406790,"owners_count":21098299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-loading","django","template-tag","websockets"],"created_at":"2025-02-20T03:18:59.533Z","updated_at":"2025-11-11T20:21:16.230Z","avatar_url":"https://github.com/diegojromerolopez.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# django-ws-include\n\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/diegojromerolopez/django-ws-include/graphs/commit-activity)\n[![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/django-ws-include.svg)](https://pypi.python.org/pypi/django-ws-include/)\n[![PyPI version django-ws-include](https://badge.fury.io/py/django-ws-include.svg)](https://pypi.python.org/pypi/django-ws-include/)\n[![PyPI status](https://img.shields.io/pypi/status/django-ws-include.svg)](https://pypi.python.org/pypi/django-ws-include/)\n[![PyPI download month](https://img.shields.io/pypi/dm/django-ws-include.svg)](https://pypi.python.org/pypi/django-ws-include/)\n[![Maintainability](https://api.codeclimate.com/v1/badges/25ec3d6c327ca2ef3ea1/maintainability)](https://codeclimate.com/github/diegojromerolopez/django-ws-include/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/25ec3d6c327ca2ef3ea1/test_coverage)](https://codeclimate.com/github/diegojromerolopez/django-ws-include/test_coverage)\n\nInclude your templates asynchronously and load their contents using websockets\nin [Django](https://www.djangoproject.com/).\n\n[See this library in github](https://github.com/diegojromerolopez/django-ws-include).\n\n## How does this work?\n\nThis library includes javascript code in the **ws_include** template_tag\nand a static javascript file\n[ws_include.js](/ws_include/static/ws_include/ws_include.js) file\n\nThat javascript code opens a websocket connection (WS_INCLUDE_WEBSOCKET)\nthat will send a websocket message including the encrypted query and the block ID of\nthe template that must be loaded asynchronously.\n\nLater, the server responds with the rendered template and the corresponding block ID.\nThe javascript code uses the block ID to identify were to include the rendered template.\n\nThis project is an optimization of\n[django-async-include](https://github.com/diegojromerolopez/django-async-include/),\nproject that while has the same philosophy, it uses HTTP requests to get the\nrendered templates, so it is less efficient than using a lone websocket connection.\nYou are encouraged to take a look to that project to help you understand the aim\nof this project.\n\n## Installation\n\n[This package is in pypi](https://pypi.org/project/django-ws-include/).\nUse pip to install it:\n\n```shell\npip install django-ws-include\n```\n\n### Installation in your Django project\n\nInclude channels and ws_include in your project's **settings.py**:\n\n```sh\n\nINSTALLED_APPS = [\n    ## ...\n    'channels',\n    'ws_include',\n]\n\n```\n\n### Create asgi.py file with django-ws-include routes\n\n```python\nimport os\n\nfrom channels.auth import AuthMiddlewareStack\nfrom channels.routing import ProtocolTypeRouter, URLRouter\nfrom django.core.asgi import get_asgi_application\nfrom ws_include.routing import websocket_urlpatterns\n\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"your_project.settings\")\n\napplication = ProtocolTypeRouter({\n    \"http\": get_asgi_application(),\n    \"websocket\": AuthMiddlewareStack(\n        URLRouter(\n            websocket_urlpatterns\n        )\n    )\n})\n\n```\n\nAdd the static file to the header of your HTML base template file:\n\n```html\n\u003cscript type=\"text/javascript\" src=\"{% static 'ws_include/ws_include.js' %}\"\u003e\u003c/script\u003e\n```\n\n## Use\n\nLoad the **ws_include** template tags at the top of your template and use the **ws_include**\ntemplate tag as a replacement of the django include template tag.\n\nYou have to pass the local context explicitly to the async included templates, so you can pass all variables you\nneed in your included template as named parameters of the **ws_include** template tag.\n\n```html\n\n{# Load the ws_include template tag at the top of your template file #}\n{% load ws_include %}\n\n{# Call the ws_include template tag indicating what objects needs to replace it #}\n{% ws_include \"\u003cpath of the \u003e\" \u003cobject1_name\u003e=\u003cobject1\u003e \u003cobject2_name\u003e=\u003cobject2\u003e ... \u003cobjectN_name\u003e=\u003cobjectN\u003e  %}\n```\n\nThere is also a repository with a full example that also uses django-async-include:\n[django-async-include-example](https://github.com/diegojromerolopez/django-async-include-example).\n\n### Warning and limitations\n\n#### Object dynamic attributes\nNo dynamic attribute will be passed to the templates given that only a reference to it is passed\nfrom the caller to the included template callee.\n\n**Don't use dynamic attributes inside an async_included template**.\n\nHowever, the full object will be passed to the template,\nso you could call its methods and properties without any problem.\n\n#### QuerySets\nEach QuerySet is passed as encrypted SQL and converted on the receiver to a RawQuerySet.\n\nNote that RawQuerySets have no len method so length filter returns always 0.\n\n**Load ws_included_length in your template and use the filter **ws_included_length** to get the length.\n\n````html\n{# Partial HTML template file to be loaded by websockets #}\n{% load ws_included_length %}\n\n\u003cdiv\u003e\n    \u003ch2\u003eProduct list (items|ws_included_length)\u003c/h2\u003e\n    \u003cul\u003e\n        {% for item in items %}\n        \u003cli\u003e\n            {{ item.name }}\n        \u003c/li\u003e\n        {% endfor %}\n    \u003c/ul\u003e\n\u003c/div\u003e\n````\n\n## Examples\n\n### Passing an object\n\n```html\n{% load ws_include %}\n\n{# .. #}\n\n{# Load the template and informs the board object is required for the included template  #}\n{% ws_include \"boards/components/view/current_percentage_of_completion.html\" board=board %}\n```\n\n### Passing a QuerySet\n\n```html\n{% load ws_include %}\n\n{# .. #}\n\n{% ws_include \"boards/components/view/summary.html\" board=board member=member next_due_date_cards=next_due_date_cards %}\n```\n\n## Customization\n\n### Block wrapper html tag\n\nWrapper tag is **div** and maybe you don't want that. Set **html__tag** optional parameter to the name of\nthe tag you need in that particular context.\n\nExample:\n\n```html\n{% load ws_include %}\n\n{# .. #}\n\n{# Will be replaced by \u003cli\u003e\u003c/li\u003e block instead of \u003cdiv\u003e\u003c/div\u003e #}\n{% ws_include \"boards/components/view/last_comments.html\" board=board html__tag='li' %}\n```\n\n### Block wrapper html tag class\n\nCustomize the wrapper class by passing **html__tag__class** optional parameter to the template tag.\n\n```html\n{% load ws_include %}\n\n{# .. #}\n\n{# Will be replaced by \u003cli\u003e\u003c/li\u003e block instead of \u003cdiv\u003e\u003c/div\u003e #}\n{# Class last_comments will be added to wrapper class #}\n{% ws_include \"boards/components/view/last_comments.html\" board=board html__tag='li' html__tag__class='last_comments' %}\n```\n\n## TODO\n* More tests: test the Websocket Consumer code.\n* Improve documentation.\n\n## Main author\nDiego J. Romero-López is a Software Engineer based on Madrid (Spain).\n\nThis project is in no way endorsed or related in any way to my past or current employers.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiegojromerolopez%2Fdjango-ws-include","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiegojromerolopez%2Fdjango-ws-include","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiegojromerolopez%2Fdjango-ws-include/lists"}