-
-
Notifications
You must be signed in to change notification settings - Fork 22
Passing a large query through a Django template #118
-
This may be Django-specific. Let's say I have a view that summons a Django template to a display a long table of widgets, where each widget is an idom component (correponding to a record from a DB table). As far as I understand, I can pass at most JSONs from a template to a component via {% component ... %} -- so each has to refetch its record from the DB if I want to have it (in serial, with use_query). Should I use_context in the view and the component to share a large query? I feel like I'm missing something...
Thank you.
Beta Was this translation helpful? Give feedback.
All reactions
This limitation will be resolved in v3.0.0
Template tag parameters will now have unrestricted arg/kwarg values. Thus, they will perform identically to a typical Django template tag.
See the following PR for more details:
Replies: 4 comments 15 replies
-
If you need "shared data" between several components, you need to create one parent component to contain all your sub-components.
You should use use_query within the parent component. This parent component can either provide the query data to the subcomponents via args/kwargs, or via use_context.
Beta Was this translation helpful? Give feedback.
All reactions
-
Instead of defining the outer table with a template in Django, it would probably be best to do so using IDOM. This way, you can define an outer component that performs one large query and returns a table of widgets where the data from that query is disseminated to those widgets. As mentioned in this answer, you can pass data from that query in two ways - either passing the data down to the components with arguments, or if the components which actually consume the data are sufficiently deep such that passing arguments would be tedious, you can use_context. Unfortunately, we don't have documentation for use_context yet, but React's docs are usually similar enough that you can reference those (especially with respect to best practices and general patterns).
With all that said, here's what that outer table component could look like with and without using a context:
Without context
from idom import component, html from django_idom import use_query @component def Table(): data_query = use_query(get_the_data) if data_query.loading: return html.h2("Loading...") elif data_query.error: return html.h2("Error!") return html.table( Row(row, key=row.some_unique_id_from_your_data) for row in data_query.data ) @component def Row(row_data): return html.tr(...) # render a table row somehow def get_the_data(): ...
Using context
from idom import component, html, create_context, use_context from django_idom import use_query TableDataContext = create_context(None) @component def Table(): data_query = use_query(get_the_data) if data_query.loading: return html.h2("Loading...") elif data_query.error: return html.h2("Error!") return TableDataContext( html.table( RowContainerOuter(key=row.some_unique_id_from_your_data) for row in data_query.data ), value=data_query.data ) @component def RowContainerOuter(): return html.tr(RowContainerInner()) @component def RowContainerInner(): return html.tr(Row()) @component def Row(): row_data = use_context(TableDataContext) return ... # render a table row somehow def get_the_data(): ...
Beta Was this translation helpful? Give feedback.
All reactions
-
Thank you both for the answers. Yes, I considered doing it this way, @rmorshea, but I think this is leaving too much Django functionality on the table.
Anyway, I looked 'under the hood', and my issue seems more related to django-idom==2.1.0. Let me know if I should move it there somehow.
So, I saw that the template tag component accepts a dotted_path and kwargs. The kwargs are jsonized, fine. The dotted_path is interpreted/imported as a callable, the kwargs are dumped there. I suppose this is the crucial line in consumer.py (django_idom):
component_instance = component_constructor(**component_kwargs)
I'd like to have an option to pass the Django context also. This seems very natural. I probably wouldn't change the above part, but redefine the callable component_constructor by binding context to the first argument, say, before it lands in IDOM_REGISTERED_COMPONENTS. So, perhaps inside the component tag definition, this line
_register_component(dotted_path)
would be
_register_component(context, dotted_path)
and therein,
IDOM_REGISTERED_COMPONENTS[dotted_path] = partial(_import_dotted_path(dotted_path), context)
What do you think?
Since I can pass anything to an idom component, I don't see why it shouldn't be possible for a template tag.
Beta Was this translation helpful? Give feedback.
All reactions
-
Thinking about it now, using database-backed component_kwargs might be mandatory.
If the component has a kwarg called is_admin, it's currently fairly trivial to edit the page HTML and set that to true within the JSON parameters.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Agreed. Too much room for error there.
Beta Was this translation helpful? Give feedback.
All reactions
-
I will PR this ASAP.
Beta Was this translation helpful? Give feedback.
All reactions
-
Before making a PR, can you lay out the approach in an issue? I just want to be sure we hash out all the subtleties. For example, is this data transient? If so, how do we clean up the data when it's no longer needed. If not, then unpickling previously stored objects could be an issue if users upgrade their Python version.
Beta Was this translation helpful? Give feedback.
All reactions
-
Beta Was this translation helpful? Give feedback.
All reactions
-
This limitation will be resolved in v3.0.0
Template tag parameters will now have unrestricted arg/kwarg values. Thus, they will perform identically to a typical Django template tag.
See the following PR for more details:
Beta Was this translation helpful? Give feedback.
All reactions
-
Fwiw, I think this is great (and having tested my proposal above: it was crap).
I wonder about two things:
- Will {% component %} work as expected if invoked with different parameters from within a {% for %} loop in a template? In other words, what is the default 'key'?
- What changes to the objects passed as arguments will trigger an update of the component (I suppose none by default)?
Beta Was this translation helpful? Give feedback.
All reactions
-
- Will {% component %} work as expected if invoked with different parameters from within a {% for %} loop in a template? In other words, what is the default 'key'?
- Yes, each individual component is it's own unique ReactJS DOM tree. Therefore, even if the
keyof the top level node is identical it won't matter.
- Yes, each individual component is it's own unique ReactJS DOM tree. Therefore, even if the
- What changes to the objects passed as arguments will trigger an update of the component (I suppose none by default)?
- Any time the Django template is re-rendered, the components will be re-rendered as well.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1