Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Passing a large query through a Django template #118

Answered by Archmonger
numpde asked this question in Question
Discussion options

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.

You must be logged in to vote

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

Comment options

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.

You must be logged in to vote
0 replies
Comment options

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():
 ...
You must be logged in to vote
0 replies
Comment options

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.

You must be logged in to vote
13 replies
Comment options

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.

Comment options

Agreed. Too much room for error there.

Comment options

I will PR this ASAP.

Comment options

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.

Comment options

Comment options

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:

You must be logged in to vote
2 replies
Comment options

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)?
Comment options

  • 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 key of the top level node is identical it won't matter.
  • 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.
Answer selected by Archmonger
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /