{"id":15295744,"url":"https://github.com/joshiggins/django-view-composer","last_synced_at":"2025-10-07T08:30:36.905Z","repository":{"id":44754006,"uuid":"448235486","full_name":"joshiggins/django-view-composer","owner":"joshiggins","description":"We heard you like views so we put class based views in your class based views","archived":true,"fork":false,"pushed_at":"2022-03-05T22:29:19.000Z","size":52,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-09T16:56:50.817Z","etag":null,"topics":["classbasedviews","components","django","htmx","python"],"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/joshiggins.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-15T09:35:49.000Z","updated_at":"2023-10-05T11:36:44.000Z","dependencies_parsed_at":"2022-08-22T10:00:48.848Z","dependency_job_id":null,"html_url":"https://github.com/joshiggins/django-view-composer","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshiggins%2Fdjango-view-composer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshiggins%2Fdjango-view-composer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshiggins%2Fdjango-view-composer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshiggins%2Fdjango-view-composer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joshiggins","download_url":"https://codeload.github.com/joshiggins/django-view-composer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235607123,"owners_count":19017298,"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":["classbasedviews","components","django","htmx","python"],"created_at":"2024-09-30T18:07:52.891Z","updated_at":"2025-10-07T08:30:29.502Z","avatar_url":"https://github.com/joshiggins.png","language":"Python","readme":"# Django View Composer\n\nExtending the Django template system so that you can include a view inside another view\n\n- **Simple view composition** - based on template tags\n- **Reusable components** - turn any class based view into a reusable component\n- **Lightweight** - no framework, no core Javascript and no additional Python dependencies\n- **Reactive, if you want** - integrates nicely with HTMX\n\n```html+django\n{% load view_composer %}\n\n\u003cnav\u003e\n   {% view 'myapp.views.NavBar' %}\n\u003c/nav\u003e\n\n{% viewblock 'myapp.views.ListView' %}\n   {% view 'myapp.views.ListFilter' %}\n{% endviewblock %}\n```\n\n## Quick start\n\nDjango View Composer is released on PyPi so you can install using Pip:\n\n```sh\npip install django-view-composer\n```\n\nor Poetry:\n\n```sh\npoetry install django-view-composer\n```\n\nOnce installed, add to your `INSTALLED_APPS` setting to register the template tags:\n\n```python\nINSTALLED_APPS = [\n    ...\n    \"django_view_composer\",\n    ...\n]\n```\n\n## Using the `view` tag\n\nThe `{% view %}` tag renders a class based view and includes the content in the current template.\n\nIt has 1 required argument which is the import string for the view:\n\n```html+django\n{% load view_composer %}\n\n{% view 'myapp.views.MyView' %}\n```\n\nYou can also provide a variable for the import string which will be resolved from the current template's context:\n\n```html+django\n{% view view_to_render %}\n```\n\n### Context variables\n\nSimilar to the `{% include %}` tag which operates on templates, the included view will be provided with the same context variables from the current template it is being rendered into.\n\nThese are provided as extra, so they won't replace any context variables the child view might be setting itself.\n\nIf any context variable names conflict, whatever the child view sets in it's own `get_context_data` will take precedence.\n\nYou can pass additional context from the template tag:\n\n```html+django\n{% view 'myapp.views.MyView' with foo='bar' %}\n```\n\nAdditional variables can be resolved from the current template's context to pass to the included view:\n\n```html+django\n{% view 'myapp.views.MyView' with foo=foo %}\n```\n\n### Use `only` to limit context\n\nIf you want to render the included view only with the variables provided (or even no variables at all), use the only option. No other variables will be provided to the included view.\n\n```html+django\n{% view 'myapp.views.MyView' with foo='bar' only %}\n```\n\n### View keyword arguments\n\nIf your view requires kwargs in the URL, such as a pattern like\n\n```python\nurl_patterns = [\n    path(\"item/\u003cpk:pk\u003e/edit\", ItemEditView.as_view(), name=\"item-edit-view\"),\n]\n```\n\nyou can supply these in the template tag directly after the import string and before the `with` keyword:\n\n```html+django\n{% view 'myapp.views.ItemEditView' pk=pk with extra_food=\"spam\" %}\n```\n\nor without any extra context variables:\n\n```html+django\n{% view 'myapp.views.ItemEditView' pk=pk %}\n```\n\n\u003e These kwargs are the ones passed to the view's `setup()`, not to the `__init__` method\n\n## Using the `viewblock` tag\n\nThe `{% viewblock %}` tag renders a class based view and includes the content in the current template, but provides a block for additional nodes which are rendered first and made available in the included view’s context.\n\nThis tag must be closed with a corresponding endviewblock. It has 1 required argument which is the import string for the view:\n\n```html+django\n{% load view_composer %}\n\n{% viewblock 'myapp.views.MyView' %}\n    \u003ch2\u003eAn excellent view!\u003c/h2\u003e\n{% endviewblock %}\n```\n\nIn the template for the `myapp.views.MyView`, you can use the children context variable to decide where to render the block content:\n\n```html+django\n\u003cdiv\u003e\n    {{ children }}\n\u003c/div\u003e\n```\n\nContext variables are supported in the same way as the `view` tag.\nHowever, since the block content is rendered _before_ the included view, the additional nodes in the block can only access the current template's context - not the context of the view being included.\n\n## Nesting views\n\nTwo different forms of nesting are possible\n\n- you can put a `{% view %}` or a `{% viewblock %}` inside a `{% viewblock %}` in the same template\n- you can include a view where its own template includes other views\n\nViews are rendered in the order that the tags appear in the template.\n\nA `{% viewblock %}` renders the block content _first_ and then renders the view being included.\n\n## Handling POST views\n\nMost of the time the views being composed will have GET handlers which return a template response.\n\nOne of the powerful features of view composition (compared to template includes) is the ability to bring in additional logic, such as including a view which handles a form.\n\nHowever, included views are all rendered with the same HTTP request object which originates from the root view - the top most one which was handled by a URL pattern.\n\nIf you need to handle a different method in an included view, such as a child view that contains a form POST, you must\n\n- map the included view to a URL pattern as well\n- make the request to the view's direct URL, instead of the current URL, when it is submitted\n\nUsing the form as an example:\n\n```python\nfrom .views import ItemCreateView\n\napp_name = \"myapp\"\nurl_patterns = [\n    path(\"item/create\", ItemCreateView.as_view(), name=\"item-create-view\"),\n]\n```\n\n```html+django\n\u003cform method=\"post\" action=\"{% url 'myapp:item-create-view' %}\"\u003e\n    ...\n\u003c/form\u003e\n```\n\nNow you can include this view inside another one like `{% view 'myapp.views.ItemCreateView' %}` and when the form is POSTed it will send the request to the correct view.\n\n### Modify view dispatch\n\nIn some cases you might need to modify how the view is dispatched so it works well when included inside another (or several levels of) view.\n\nFor example, the Django generic editing views usually return a redirect response. You might want to return another blank instance of the form in the response to a successful POST, or you might want to return a confirmation with an 'Add another' button to bring up a new form.\n\nDjango View Composer will not render anything if the view being included does not return a template response.\n\n## Reactive\n\nAn important concept in the view composer is that _the same views can be included via a template tag or rendered normally via a URL pattern_. \n\nThis provides a foundation for reactivity when coupled with [HTMX](https://htmx.org):\n\n- **initial render of the page** - including views via template tags\n- **reactive updates of individual views on a page** - calling the view's direct URL pattern and replacing the content in the page\n\nRemember, the view composer is not a framework - its just a template tag that lets you render a view inside another view.\nIt does not fundamentally change the Django request lifecycle even if you choose to include some reactivity with HTMX.\n\n## Running tests\n\nThere is a growing test suite which can be run \n\n```\n$ poetry install\n$ poetry shell\n$ cd tests\n$ ./manage.py test\n```\n\n## Contributing\n\nWelcome!","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshiggins%2Fdjango-view-composer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshiggins%2Fdjango-view-composer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshiggins%2Fdjango-view-composer/lists"}