From aec96642d38a534b2f3a058c8fd95babdfc350b0 Mon Sep 17 00:00:00 2001 From: Josh Higgins <5124298+joshiggins@users.noreply.github.com> Date: Mon, 24 Jan 2022 22:26:51 +0000 Subject: [PATCH 1/3] allow passing view kwargs before 'with' --- .../templatetags/view_composer.py | 18 ++++++++++++++++-- tests/basic/tests.py | 11 ++++++++++- tests/basic/views.py | 11 +++++++++-- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/django_view_composer/templatetags/view_composer.py b/django_view_composer/templatetags/view_composer.py index c8d1315..d736f0d 100644 --- a/django_view_composer/templatetags/view_composer.py +++ b/django_view_composer/templatetags/view_composer.py @@ -34,6 +34,11 @@ def parse_view_tag(parser, token): options["no_parent_ctx"] = True options["vars"] = token_kwargs(arg_group[2], parser) + # kwargs for the view should preceed the 'with' bit + arg_group[0].pop(0) + if len(arg_group[0]) > 0: + options["kwargs"] = token_kwargs(arg_group[0], parser) + return options @@ -79,6 +84,12 @@ def render(self, context): for k in self.options["vars"]: child_context[k] = self.options["vars"][k].resolve(context) + # resolve the kwargs + resolved_kwargs = {} + if "kwargs" in self.options: + for k in self.options["kwargs"]: + resolved_kwargs[k] = self.options["kwargs"][k].resolve(context) + # render any nodes in the block first and add these to the child # view context if self.nodelist: @@ -87,12 +98,15 @@ def render(self, context): # render the view to a response instance = view_class(request=request, extra_context=child_context) + # call setup on the view + instance.setup(request, **resolved_kwargs) + # if the view class has a compose method use that, otherwise # default to get method if hasattr(instance, "compose"): - response = instance.compose(request) + response = instance.compose(request, **resolved_kwargs) else: - response = instance.get(request) + response = instance.get(request, **resolved_kwargs) # only render if there is something to render if hasattr(response, "render"): diff --git a/tests/basic/tests.py b/tests/basic/tests.py index 9dba0f5..10efe4b 100644 --- a/tests/basic/tests.py +++ b/tests/basic/tests.py @@ -97,4 +97,13 @@ def test_nested_block_views(self): {"food": "spam"}, ) test_ctx = jsonpickle.decode(res) - self.assertEqual(test_ctx["food"], "spam") \ No newline at end of file + self.assertEqual(test_ctx["food"], "spam") + + def test_view_kwargs(self): + res = self.get_with_context( + "{% load view_composer %}" + "{% view 'basic.views.KwargsTestView' food='spam' with ham='eggs' %}", {} + ) + test_ctx = jsonpickle.decode(res) + self.assertEqual(test_ctx["food_kwarg"], "spam") + self.assertEqual(test_ctx["ham"], "eggs") \ No newline at end of file diff --git a/tests/basic/views.py b/tests/basic/views.py index 34ebc89..11b855c 100644 --- a/tests/basic/views.py +++ b/tests/basic/views.py @@ -10,9 +10,16 @@ class ContextTestView(TemplateView): template_name = "basic/context.html" def get_context_json(self): - context = self.get_context_data() + context = self.get_context_data(**self.kwargs) return jsonpickle.encode(context) class BlockTestView(TemplateView): - template_name = "basic/block.html" \ No newline at end of file + template_name = "basic/block.html" + + +class KwargsTestView(ContextTestView): + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["food_kwarg"] = kwargs["food"] + return context \ No newline at end of file From 7c4af96be6746f05650706bda786f26e09e8aad1 Mon Sep 17 00:00:00 2001 From: Josh Higgins <5124298+joshiggins@users.noreply.github.com> Date: Mon, 24 Jan 2022 22:32:32 +0000 Subject: [PATCH 2/3] update readme with kwargs --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index aa5da62..10bf0bc 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,30 @@ If you want to render the included view only with the variables provided (or eve {% view 'myapp.views.MyView' with foo='bar' only %} ``` +### View keyword arguments + +If your view requires kwargs in the URL, such as a pattern like + +```python +url_patterns = [ + path("item//edit", ItemEditView.as_view(), name="item-edit-view"), +] +``` + +you can supply these in the template tag directly after the import string and before the `with` keyword: + +```html+django +{% view 'myapp.views.ItemEditView' pk=pk with extra_food="spam" %} +``` + +or without any extra context variables: + +```html+django +{% view 'myapp.views.ItemEditView' pk=pk %} +``` + +> These kwargs are the ones passed to the view's `setup()`, not to the `__init__` method + ## Using the `viewblock` tag The `{% 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. From ed5a13c5a2a12a23a4fa37bdcac55f0b90aeddc1 Mon Sep 17 00:00:00 2001 From: Josh Higgins <5124298+joshiggins@users.noreply.github.com> Date: Mon, 24 Jan 2022 22:35:24 +0000 Subject: [PATCH 3/3] add test for kwarg in viewblock --- tests/basic/tests.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/basic/tests.py b/tests/basic/tests.py index 10efe4b..bdd682c 100644 --- a/tests/basic/tests.py +++ b/tests/basic/tests.py @@ -102,7 +102,19 @@ def test_nested_block_views(self): def test_view_kwargs(self): res = self.get_with_context( "{% load view_composer %}" - "{% view 'basic.views.KwargsTestView' food='spam' with ham='eggs' %}", {} + "{% view 'basic.views.KwargsTestView' food='spam' with ham='eggs' %}", + {}, + ) + test_ctx = jsonpickle.decode(res) + self.assertEqual(test_ctx["food_kwarg"], "spam") + self.assertEqual(test_ctx["ham"], "eggs") + + def test_viewblock_kwargs(self): + res = self.get_with_context( + "{% load view_composer %}" + "{% viewblock 'basic.views.KwargsTestView' food='spam' with ham='eggs' %}" + "{% endviewblock %}", + {}, ) test_ctx = jsonpickle.decode(res) self.assertEqual(test_ctx["food_kwarg"], "spam")