Delay loading component until rendering, and clean up usage of component variable.

This commit is contained in:
Emil Stenström 2022-07-14 12:47:06 +02:00
parent 235c34a986
commit 29e6d1a4a0

View file

@ -119,11 +119,11 @@ def component_js_dependencies_tag(preload=""):
def do_component(parser, token):
bits = token.split_contents()
bits, isolated_context = check_for_isolated_context_keyword(bits)
component, context_args, context_kwargs = parse_component_with_args(
component_name, context_args, context_kwargs = parse_component_with_args(
parser, bits, "component"
)
return ComponentNode(
component,
component_name,
context_args,
context_kwargs,
isolated_context=isolated_context,
@ -131,9 +131,8 @@ def do_component(parser, token):
class SlotNode(Node):
def __init__(self, name, nodelist, component=None):
self.name, self.nodelist, self.component = name, nodelist, component
self.component = None
def __init__(self, name, nodelist):
self.name, self.nodelist = name, nodelist
self.parent_component = None
self.context = None
@ -144,7 +143,7 @@ class SlotNode(Node):
# Thread safety: storing the context as a property of the cloned SlotNode without using
# the render_context facility should be thread-safe, since each cloned_node
# is only used for a single render.
cloned_node = SlotNode(self.name, self.nodelist, self.component)
cloned_node = SlotNode(self.name, self.nodelist)
cloned_node.parent_component = self.parent_component
cloned_node.context = context
@ -174,7 +173,7 @@ class SlotNode(Node):
@register.tag("slot")
def do_slot(parser, token, component=None):
def do_slot(parser, token):
bits = token.split_contents()
if len(bits) != 2:
raise TemplateSyntaxError("'%s' tag takes only one argument" % bits[0])
@ -183,7 +182,7 @@ def do_slot(parser, token, component=None):
nodelist = parser.parse(parse_until=["endslot"])
parser.delete_first_token()
return SlotNode(slot_name, nodelist, component=component)
return SlotNode(slot_name, nodelist)
class ComponentNode(Node):
@ -195,7 +194,7 @@ class ComponentNode(Node):
def __init__(
self,
component,
component_name,
context_args,
context_kwargs,
slots=None,
@ -203,33 +202,31 @@ class ComponentNode(Node):
):
self.context_args = context_args or []
self.context_kwargs = context_kwargs or {}
self.component, self.isolated_context = component, isolated_context
self.component_name, self.isolated_context = (
component_name,
isolated_context,
)
self.slots = slots
def __repr__(self):
return "<Component Node: %s. Contents: %r>" % (
self.component,
getattr(self.component.instance_template, "nodelist", None),
self.component_name,
self.nodelist,
)
def render(self, context):
if type(self.component) == str:
try:
component_name = template.Variable(self.component).resolve(
context
)
component_class = registry.get(component_name)
self.component = component_class(component_name)
except:
raise TemplateSyntaxError(
f"Component name is not defined or not registred: {self.component}"
)
# Group slot notes by name and concatenate their nodelists
self.component.slots = defaultdict(NodeList)
component_name = template.Variable(self.component_name).resolve(
context
)
component_class = registry.get(component_name)
component = component_class(component_name)
# Group slot notes by name and concatenate their nodelists
component.slots = defaultdict(NodeList)
for slot in self.slots or []:
self.component.slots[slot.name].extend(slot.nodelist)
self.should_render_dependencies = is_dependency_middleware_active()
self.component.outer_context = context.flatten()
component.slots[slot.name].extend(slot.nodelist)
component.outer_context = context.flatten()
# Resolve FilterExpressions and Variables that were passed as args to the component, then call component's
# context method to get values to insert into the context
@ -240,7 +237,7 @@ class ComponentNode(Node):
key: safe_resolve(kwarg, context)
for key, kwarg in self.context_kwargs.items()
}
component_context = self.component.get_context_data(
component_context = component.get_context_data(
*resolved_context_args, **resolved_context_kwargs
)
@ -249,11 +246,11 @@ class ComponentNode(Node):
context = context.new()
with context.update(component_context):
rendered_component = self.component.render(context)
if self.should_render_dependencies:
rendered_component = component.render(context)
if is_dependency_middleware_active():
return (
RENDERED_COMMENT_TEMPLATE.format(
name=self.component._component_name
name=component._component_name
)
+ rendered_component
)
@ -278,16 +275,15 @@ def do_component_block(parser, token):
bits = token.split_contents()
bits, isolated_context = check_for_isolated_context_keyword(bits)
component, context_args, context_kwargs = parse_component_with_args(
component_name, context_args, context_kwargs = parse_component_with_args(
parser, bits, "component_block"
)
return ComponentNode(
component,
component_name,
context_args,
context_kwargs,
slots=[
do_slot(parser, slot_token, component=component)
for slot_token in slot_tokens(parser)
do_slot(parser, slot_token) for slot_token in slot_tokens(parser)
],
isolated_context=isolated_context,
)
@ -368,17 +364,8 @@ def parse_component_with_args(parser, bits, tag_name):
"Call the '%s' tag with a component name as the first parameter"
% tag_name
)
if not is_wrapped_in_quotes(component_name):
# raise TemplateSyntaxError(
# "Component name '%s' should be in quotes" % component_name
# )
component = component_name
else:
trimmed_component_name = component_name[1:-1]
component_class = registry.get(trimmed_component_name)
component = component_class(trimmed_component_name)
return component, context_args, context_kwargs
return component_name, context_args, context_kwargs
def safe_resolve(context_item, context):