I used to use Lodash template()
until I give up due to the verbosity of the interpolation delimiters used. They're a pain, especially when it's a simple string I want to build. Stylistically, I don't want to resort to string concatenation in my code, but, it turned out to be the better option. You can use Lodash for simple string-building scenarios such as these — it just requires a little tweaking.
Showing posts with label template. Show all posts
Showing posts with label template. Show all posts
Tuesday, July 8, 2014
Simpler Lodash Templates
Thursday, January 23, 2014
Handlebars Helpers vs String Utilities
The Handlebars client-side template system let's the developer register new template helpers. In effect, this extends the template syntax, adding to the short list of available helpers. The decision to include as few helpers as possible in the package was an intentional one - there's no sense including a lot of stuff that nobody uses. Especially when it's easy enough to make your own using registerHelper(). For this reason, only the bare essentials such as if
and each
are available out of the box. But is there an alternative approach to formatting your template data?
Labels:
handlebars
,
helpers
,
template
,
utility
Thursday, October 3, 2013
Widgets, Templates, and DRY
Widgets are just templates. Simply put, yes, but it's true at one level or another. There are many ways a front-end developer can go about designing and implementing widgets — using frameworks made for such a purpose, or just staying consistent with your own patterns and principles. Who knows, maybe if you're of the latter camp, you eventually roll your own framework that supersedes anything that's on the market. And the funny thing is, you didn't set out to dominate a technology area — it just happened as a result of ironing out your own development pains. This is true of many, many successful open source projects.
Thursday, November 3, 2011
Preferring Filters To Tags
In Django, there are two ways to extend the template language — tags and filters. Tags are named tokens that insert HTML, executing logic behind the scenes. For instance, an if tag and a for tag will conditionally produce content or iterate over a list objects respectfully. The if tag in Django takes an argument — the condition to evaluate.
Filters, on the other hand, are different from tags — they don't spit out HTML markup or alter the overall template logic. Instead, filters modify existing values in the template context for the sake of presentation. For example, Django ships with a fileformat filter that'll display the argument, expressed in bytes, as a more readable representation. This type of functionality is best encapsulated inside a filter because we're simply modifying the presentation of a single value.
I used to find myself grappling over whether something should be implemented as a tag or as a filter. On the one hand, custom tags capacious changes — chunks of HTML or logic for manipulating the template. On the other hand, filters are concise. They take input and modify it. Filters exchange one piece of data for another. Django provides the machinery to do this, to slice up monolithic templates into reusable, independent components. My inclination is that custom template tags can often be avoided in favor of included templates and filters.
Modular templates
If every page in our application were rendered using a single gargantuan template, we wouldn't be burdened with choosing between custom tags and custom filters. We'd have a number of other problems, no doubt, but I digress. Instead, Django treats template files much like Python treats modules. Django templates are modular. Why write one large template, duplicated for individual views? That approach doesn't follow the DRY principle, so we need a mechanism that'll allow us to treat our templates as components.
A component can have sub-components. This abstraction works well in the Django template architecture because components are made up of smaller components. They can be decomposed and reconstructed, using smaller, loosely-coupled components. In Django-speak, this means that we can start with a template that represents the entire page. Logically, based on the application for which this template was designed, we can map out sections of this template that are likely to appear on all pages. Things such as navigation, footer, and so forth.
These sub-components need to fill slots. These slots are called blocks, in Django. Typically, the master template is extended by descendant templates whose job is to define what fills these slots. Now we're starting to move down the composite template structure. Beyond blocks, we need something to fill them with.
Eventually, fine-grained HTML markup is generated. Some of it conditional, some of it iterative, and some using variables from the template context. But even at this level, where we're filling in blocks, there are smaller pieces still. Pieces that don't necessarily belong to a specific block. Down yet another level, we're producing markup that might even appear twice on the same page — in two distinct blocks.
As the user interface of your Django project evolves and forms it's shape, you'll begin to notice these smaller chunks — those that might be of interest to multifarious blocks. The main blocks, the logical regions of the master template are easy to grasp early on in development. It's the smaller template components — the unbound HTML markup — that are more difficult to identify. These low-level template components must take into consideration both custom template tags and custom template filters.
Sharing data
The tools that the Django template system gives developers enables the sharing of data. Sharing between what exactly? You extend the template language because you want to reuse those elements — custom tags and filters — across templates in your application. But these new elements don't generate new data. They're not storing application data. Rather, the data new template elements share is transformed data. They take input and alter what the template ultimately sends to the browser.
Let's say you've got an application that lists events of interest to the user when they first login. These are probably queried from the database and rendered inside a for tag. But maybe the event abstraction isn't limited to a user. Maybe there are different event types that pertain to other abstractions in the application and aren't exclusive to the user. Here, we might want to reuse a much of the same logic that rendered events on the homepage. We're only changing the query.
We could follow the DRY principle here and implement a custom eventlist tag. This tag would accept some type of flag, indicating the query to execute in order to render the appropriate event list. Using this tag in our templates is then quite straightforward — {% eventlist 'home' %} or {% eventlist 'updates' %}. This tag is available in all templates — an easy way to share data across Django templates.
Our tag could even take care of rendering the corresponding HTML markup. We'd simply register these eventlist tag as an inclusion tag. We've now got our own template, isolated from other templates in our user interface dedicated to rendering event lists.
There are, however, a couple problems with this approach. One, the template tag itself is responsible for executing the query. This means that our view context passed to the template during rendering cannot alter the output of the event list. So if we want to use generic views that'll generate a list of events to render, we're stuck. The eventlist tag is expecting an arbitrary flag. We've given the Django template the added responsibility of performing database queries — which isn't a good thing. We could alter our template tag so that it accepts a query set from the template context. This way the view is still responsible for retrieving objects. This is a good thing. However, this leads to another problem. One where we're violating the DRY principle.
Including and filtering
Tags are good because they're a concise way of sharing rendered HTML with other templates. Our eventlist tag does exactly that. But they're also a gateway into bad Django practice. Defining your own template tags means writing some Python code. Which gives us direct access to models. Which means we can query them. Not good. Not good as far as templates go because templates should be able to render anything I give them. If I want to pass to my tag context, say, a list of Python objects that merely emulate one of my models, it should be able to handle that. This isn't true if the template tags we define are going directly to the database for objects to render.
As for remedying the problem, we mentioned passing a query set, a list, something, to the template tag as an argument. This somewhat solves the problem because now eventlist is polymorphic to an extent. It doesn't care what objects it gets as long as they look like event objects.
Recall, however, that we're defining eventlist as an inclusion tag. This means a template dedicated to the list of events will be rendered whenever the tag is used. Keeping the HTML in the template is a smart idea — another win for us. The eventlist tag is now simply passing the list of events to render. Perfect. Except, what doesn't the template tag do now? It takes a list of objects and passes them into another template context. It does exactly what the Django include tag does.
The include tag takes a smaller template component — in our case a list of rendered event objects — and plugs it into a larger component. This sounds like an ideal candidate for our application. Our views can now control the context — the list of events that get displayed in any given block. And we're not repeating ourselves — we've got a template component that can be injected anywhere, and no need to define a custom template tag.
How about the template itself — the one we're including all over the site? Are there any drawbacks to simply including it somewhere else without using our own tag? One challenge with making template components generic enough to be used anywhere is that they need to support a variety of scenarios. What happens when the event object is in this state? When it doesn't have a title attribute? How do I handle CSS classes for events on this page?
Trying to handle all this in a single template that's used everywhere leads to messy template code. In a hurry, you've got if statements inside HTML attributes and deep nesting levels elsewhere. This is where defining custom template filters can alleviate some of these challenges. Typical Django filters will take an input value and return a slightly different version of it — like a formatted date. But we're not limited to only modifying the display of data. We can return different values entirely. Values used for the sole purpose of template rendering.
Template filter definitions are small. We might have an input value, we do a few checks, and we return a different value. Think of filters as dynamic template context modifiers — modifiers that can be shared throughout the application. Filters can also justify not having to define your own custom tags, ultimately leading to cleaner template code.
Filters, on the other hand, are different from tags — they don't spit out HTML markup or alter the overall template logic. Instead, filters modify existing values in the template context for the sake of presentation. For example, Django ships with a fileformat filter that'll display the argument, expressed in bytes, as a more readable representation. This type of functionality is best encapsulated inside a filter because we're simply modifying the presentation of a single value.
I used to find myself grappling over whether something should be implemented as a tag or as a filter. On the one hand, custom tags capacious changes — chunks of HTML or logic for manipulating the template. On the other hand, filters are concise. They take input and modify it. Filters exchange one piece of data for another. Django provides the machinery to do this, to slice up monolithic templates into reusable, independent components. My inclination is that custom template tags can often be avoided in favor of included templates and filters.
Modular templates
If every page in our application were rendered using a single gargantuan template, we wouldn't be burdened with choosing between custom tags and custom filters. We'd have a number of other problems, no doubt, but I digress. Instead, Django treats template files much like Python treats modules. Django templates are modular. Why write one large template, duplicated for individual views? That approach doesn't follow the DRY principle, so we need a mechanism that'll allow us to treat our templates as components.
A component can have sub-components. This abstraction works well in the Django template architecture because components are made up of smaller components. They can be decomposed and reconstructed, using smaller, loosely-coupled components. In Django-speak, this means that we can start with a template that represents the entire page. Logically, based on the application for which this template was designed, we can map out sections of this template that are likely to appear on all pages. Things such as navigation, footer, and so forth.
These sub-components need to fill slots. These slots are called blocks, in Django. Typically, the master template is extended by descendant templates whose job is to define what fills these slots. Now we're starting to move down the composite template structure. Beyond blocks, we need something to fill them with.
Eventually, fine-grained HTML markup is generated. Some of it conditional, some of it iterative, and some using variables from the template context. But even at this level, where we're filling in blocks, there are smaller pieces still. Pieces that don't necessarily belong to a specific block. Down yet another level, we're producing markup that might even appear twice on the same page — in two distinct blocks.
As the user interface of your Django project evolves and forms it's shape, you'll begin to notice these smaller chunks — those that might be of interest to multifarious blocks. The main blocks, the logical regions of the master template are easy to grasp early on in development. It's the smaller template components — the unbound HTML markup — that are more difficult to identify. These low-level template components must take into consideration both custom template tags and custom template filters.
Sharing data
The tools that the Django template system gives developers enables the sharing of data. Sharing between what exactly? You extend the template language because you want to reuse those elements — custom tags and filters — across templates in your application. But these new elements don't generate new data. They're not storing application data. Rather, the data new template elements share is transformed data. They take input and alter what the template ultimately sends to the browser.
Let's say you've got an application that lists events of interest to the user when they first login. These are probably queried from the database and rendered inside a for tag. But maybe the event abstraction isn't limited to a user. Maybe there are different event types that pertain to other abstractions in the application and aren't exclusive to the user. Here, we might want to reuse a much of the same logic that rendered events on the homepage. We're only changing the query.
We could follow the DRY principle here and implement a custom eventlist tag. This tag would accept some type of flag, indicating the query to execute in order to render the appropriate event list. Using this tag in our templates is then quite straightforward — {% eventlist 'home' %} or {% eventlist 'updates' %}. This tag is available in all templates — an easy way to share data across Django templates.
Our tag could even take care of rendering the corresponding HTML markup. We'd simply register these eventlist tag as an inclusion tag. We've now got our own template, isolated from other templates in our user interface dedicated to rendering event lists.
There are, however, a couple problems with this approach. One, the template tag itself is responsible for executing the query. This means that our view context passed to the template during rendering cannot alter the output of the event list. So if we want to use generic views that'll generate a list of events to render, we're stuck. The eventlist tag is expecting an arbitrary flag. We've given the Django template the added responsibility of performing database queries — which isn't a good thing. We could alter our template tag so that it accepts a query set from the template context. This way the view is still responsible for retrieving objects. This is a good thing. However, this leads to another problem. One where we're violating the DRY principle.
Including and filtering
Tags are good because they're a concise way of sharing rendered HTML with other templates. Our eventlist tag does exactly that. But they're also a gateway into bad Django practice. Defining your own template tags means writing some Python code. Which gives us direct access to models. Which means we can query them. Not good. Not good as far as templates go because templates should be able to render anything I give them. If I want to pass to my tag context, say, a list of Python objects that merely emulate one of my models, it should be able to handle that. This isn't true if the template tags we define are going directly to the database for objects to render.
As for remedying the problem, we mentioned passing a query set, a list, something, to the template tag as an argument. This somewhat solves the problem because now eventlist is polymorphic to an extent. It doesn't care what objects it gets as long as they look like event objects.
Recall, however, that we're defining eventlist as an inclusion tag. This means a template dedicated to the list of events will be rendered whenever the tag is used. Keeping the HTML in the template is a smart idea — another win for us. The eventlist tag is now simply passing the list of events to render. Perfect. Except, what doesn't the template tag do now? It takes a list of objects and passes them into another template context. It does exactly what the Django include tag does.
The include tag takes a smaller template component — in our case a list of rendered event objects — and plugs it into a larger component. This sounds like an ideal candidate for our application. Our views can now control the context — the list of events that get displayed in any given block. And we're not repeating ourselves — we've got a template component that can be injected anywhere, and no need to define a custom template tag.
How about the template itself — the one we're including all over the site? Are there any drawbacks to simply including it somewhere else without using our own tag? One challenge with making template components generic enough to be used anywhere is that they need to support a variety of scenarios. What happens when the event object is in this state? When it doesn't have a title attribute? How do I handle CSS classes for events on this page?
Trying to handle all this in a single template that's used everywhere leads to messy template code. In a hurry, you've got if statements inside HTML attributes and deep nesting levels elsewhere. This is where defining custom template filters can alleviate some of these challenges. Typical Django filters will take an input value and return a slightly different version of it — like a formatted date. But we're not limited to only modifying the display of data. We can return different values entirely. Values used for the sole purpose of template rendering.
Template filter definitions are small. We might have an input value, we do a few checks, and we return a different value. Think of filters as dynamic template context modifiers — modifiers that can be shared throughout the application. Filters can also justify not having to define your own custom tags, ultimately leading to cleaner template code.
Thursday, March 25, 2010
HTML Reuse
One of the great features of any web application framework is the HTML template. These templates allow developers to inject variables into the page. In fact, most templates allow logic to be placed directly into the HTML page (which isn't a good idea, but not really the point here).
The server, by using HTML templates, can iterate over data sets and churn out HTML that is sent to the browser. This, in effect, saves us from storing the static page structure that is then sent to the client.
This is all well and good on the server side, but what about the client? It is given a static structure to display. The browser, behind the scenes is rendering the HTML into pixel values but the HTML itself is static.
This means that HTML that can often be computed is in a static form instead. Would it not make more sense to have the Javascript of a web application build these display elements based on application data returned from the server? Maybe not the entire display but I'm sure there are many repetitive elements that can be computed rather than delivered statically.
The server, by using HTML templates, can iterate over data sets and churn out HTML that is sent to the browser. This, in effect, saves us from storing the static page structure that is then sent to the client.
This is all well and good on the server side, but what about the client? It is given a static structure to display. The browser, behind the scenes is rendering the HTML into pixel values but the HTML itself is static.
This means that HTML that can often be computed is in a static form instead. Would it not make more sense to have the Javascript of a web application build these display elements based on application data returned from the server? Maybe not the entire display but I'm sure there are many repetitive elements that can be computed rather than delivered statically.
Friday, November 6, 2009
Django Cache Nodes
As part of the Django Python web application framework is a powerful template system. Many other Python web application frameworks rely on external template rendering packages whereas Django includes this functionality. Normally, it is a good idea to not re-invent the wheel an use existing functionality provided in other packages. Especially specialized packages that do only one thing like render templates. Django, however, is a batteries-included type of framework that doesn't really have external package dependencies.
The Django templating system is not all that different from other Python template rendering systems. It is quite straightforward for both developers and for UI designers to use.
Down at the code level, everything in a template is considered to be a node. In fact, there is a Node class that every template component inherits from. It could have been named TemplateComponent but that isn't the best name for a class. Node sounds better.
One type of node that may be found in Django templates is a cache node. These are template fragments that may be stored in the Django caching system once they have been rendered. Underlying these template cache nodes is the CacheNode class and is illustrated below.
As mentioned, every Django template node type extends from the Node class and CacheNode is no different. Also, as is shown in the illustration, the render() method is overridden to provide the specific caching functionality.
Illustrated below is an activity depicting how the CacheNode.render() method will attempt to retrieve a cached version of the node that has already been rendered and return that value instead if possible.
In this illustration, we start off with two objects, cache and args. The cache object represents the Django cache system as a whole. The args object is the context of the specific node about to be rendered. Next, the context is turned into an MD5 value. The reason for this is to produce a suitable value that can used to construct a cache key. Once this operation has completed, we now have a converted copy of the context. Next, we construct a cache key. This key serves as the query we submit to the Django cache system. Next, we perform the query, asking the cache system for a value based on the key we have just constructed. Finally, if a value was returned by the cache system, this is the rendered value that we return. If now value exists in the cache system, we now need to give it one. This means that we must render the node and pass the result to the cache system and also return this rendered value.
The Django templating system is not all that different from other Python template rendering systems. It is quite straightforward for both developers and for UI designers to use.
Down at the code level, everything in a template is considered to be a node. In fact, there is a Node class that every template component inherits from. It could have been named TemplateComponent but that isn't the best name for a class. Node sounds better.
One type of node that may be found in Django templates is a cache node. These are template fragments that may be stored in the Django caching system once they have been rendered. Underlying these template cache nodes is the CacheNode class and is illustrated below.
As mentioned, every Django template node type extends from the Node class and CacheNode is no different. Also, as is shown in the illustration, the render() method is overridden to provide the specific caching functionality.
Illustrated below is an activity depicting how the CacheNode.render() method will attempt to retrieve a cached version of the node that has already been rendered and return that value instead if possible.
In this illustration, we start off with two objects, cache and args. The cache object represents the Django cache system as a whole. The args object is the context of the specific node about to be rendered. Next, the context is turned into an MD5 value. The reason for this is to produce a suitable value that can used to construct a cache key. Once this operation has completed, we now have a converted copy of the context. Next, we construct a cache key. This key serves as the query we submit to the Django cache system. Next, we perform the query, asking the cache system for a value based on the key we have just constructed. Finally, if a value was returned by the cache system, this is the rendered value that we return. If now value exists in the cache system, we now need to give it one. This means that we must render the node and pass the result to the cache system and also return this rendered value.
Wednesday, September 30, 2009
Python Cheetah Benchmark
With any web application, no matter what language it may be written in, templates need to be rendered. These are often HTML templates. If there were no templates, just static HTML files, what we would have is a static site as opposed to a web application. The dynamic aspects of the page are filled in by rendering a template. This is the most common approach for several reasons. Chiefly, the user interface is nicely separated from application logic. This, in turn, makes it easier for the user interfaces developers and designers to work without disrupting the logic they aren't concerned with. This also works vice-versa.
The Cheetah template rendering system, written for Python web applications, is a mature one. Cheetah provides a clean, elegant template syntax when compared to other Python template rendering systems. For instance, the syntax constructs are not represented as tags. This provides both flexibility and separation of concerns. Since tags aren't required, Cheetah can be used for templates other than HTML. Also, it is more obvious with Cheetah what is HTML markup and what is template markup.
Below is a very incomplete, sample of how to use Cheetah pragmatically. That is, it is very easy to plug into any potential Python system.
The Cheetah template rendering system, written for Python web applications, is a mature one. Cheetah provides a clean, elegant template syntax when compared to other Python template rendering systems. For instance, the syntax constructs are not represented as tags. This provides both flexibility and separation of concerns. Since tags aren't required, Cheetah can be used for templates other than HTML. Also, it is more obvious with Cheetah what is HTML markup and what is template markup.
Below is a very incomplete, sample of how to use Cheetah pragmatically. That is, it is very easy to plug into any potential Python system.
#Example; Timing Cheetah rendering.
#Do imports.
import timeit
from Cheetah.Template import Template
#Rendering test.
def render_cheetah():
#Cheetah template string.
template_str="""<html>
<head>
<title>$title</title>
</head>
<body>$body</body>
</html>"""
#The context supplied to the template; variable substitution.
context={"title":"Cheetah Test", "body":"Cheetah Test"}
#Initialize the Cheetah template object.
template_obj=Template(template_str, searchList=[context])
#Render the template.
str(template_obj)
#Main.
if __name__=="__main__":
#Run the test an print the results.
cheetah_timer=timeit.Timer("render_cheetah()",\
"from __main__ import render_cheetah")
print "Cheetah:",cheetah_timer.timeit(number=1000)
Labels:
cheetah
,
markup
,
python
,
template
,
templateengine
Tuesday, September 22, 2009
Simply HTML
Generating HTML markup in Python applications does not always mean resorting to rendering templates. Using templates to implement the views of an application on the web is a standard practice because it helps to remove the presentation layer. That being said, there is nothing to stop a standard Python module from generating markup while only being concerned with the presentation, not the application logic.
The html Python package provides a very simplistic method in which to generate HTML pragmatically. There is nothing wrong with using this approach as long as the separation of concerns principal is obeyed. This Python package allows developers to generate markup with a single HTML class. This class isn't meant to act as a singleton, but, rather, as a logically-separated string. There is nothing preventing developers from combining HTML instances to provide the final rendering.
The two main features of these HTML instances are that they use simple element methods to construct elements. This adds a nice self-containment to the document while it is under construction. The HTML instances also support the with statement. This provides a context for building child elements as is illustrated below.
The html Python package provides a very simplistic method in which to generate HTML pragmatically. There is nothing wrong with using this approach as long as the separation of concerns principal is obeyed. This Python package allows developers to generate markup with a single HTML class. This class isn't meant to act as a singleton, but, rather, as a logically-separated string. There is nothing preventing developers from combining HTML instances to provide the final rendering.
The two main features of these HTML instances are that they use simple element methods to construct elements. This adds a nice self-containment to the document while it is under construction. The HTML instances also support the with statement. This provides a context for building child elements as is illustrated below.
#Example; Using the html package.
#Get the HTML class.
from html import HTML
#Main.
if __name__=="__main__":
#Instantiate an HTML document.
html_obj=HTML()
#Construct a HTML element and provide a context.
with html_obj.html():
#Construct a body element with a class,
#and provide a context.
with html_obj.body(klass="my-body"):
#Construct some body elements.
html_obj.h1("Testing 123", klass="my-header")
html_obj.p("Hello World!", klass="my-text")
#Display the markup.
print html_obj
Monday, May 4, 2009
Django Templates and NodeLists
Whether dealing with a complex web application or a simple web site with relatively few pages, using templates is generally a good idea. With complex page structures, this is unavoidable. The alternative would be to implement the page structure manually. Even with simplistic web pages, there is often a dynamic element that is undesirable to manually edit. If the web application is built with a Python web application, developers have several template engines to choose from. TuboGears, for instance, offers support for several third-party template engines. Django, on the other hand, offers their own template rendering system. The Django template engine provides many of the same features as do other Python template engines. The syntax used in Django templates is simplistic and easy to use. Inside the template engine are two closely related classes that represent key template concepts and are illustrated below. These classes are Template and NodeList.
The Template class represents a template in its' entirety. During the construction of Template instances, the template is compiled. Since this process takes place in the Template constructor, the template string is a required constructor parameter. Since any given Template instance is compiled, it may be rendered at any time. The template passed to the constructor is only compiled once since the compilation takes place in the constructor. Template instances support iteration. Each iteration through a particular Template instance yields a node from the NodeList instance that resulted from compiling the template. Invoking Template.render() will in turn invoke NodeList.render(), passing along the specified context.
The NodeList represents a collection of nodes that result from compiling a template string. The majority of these nodes are HTML elements, template variables, or some Python language construct such as an if statement. NodeList instances are also instances of the Python list primitive. This means that each node contained within the list behaves just like a Python list element. The NodeList.render() method will cumulatively invoke render() on each node contained within the list. The end result is the rendered template. This rendering behavior provided by the NodeList.render() method can be considered polymorphic. The method iteratively invokes render() on anonymous instances. All it cares about is the render() interface.
The Template class represents a template in its' entirety. During the construction of Template instances, the template is compiled. Since this process takes place in the Template constructor, the template string is a required constructor parameter. Since any given Template instance is compiled, it may be rendered at any time. The template passed to the constructor is only compiled once since the compilation takes place in the constructor. Template instances support iteration. Each iteration through a particular Template instance yields a node from the NodeList instance that resulted from compiling the template. Invoking Template.render() will in turn invoke NodeList.render(), passing along the specified context.
The NodeList represents a collection of nodes that result from compiling a template string. The majority of these nodes are HTML elements, template variables, or some Python language construct such as an if statement. NodeList instances are also instances of the Python list primitive. This means that each node contained within the list behaves just like a Python list element. The NodeList.render() method will cumulatively invoke render() on each node contained within the list. The end result is the rendered template. This rendering behavior provided by the NodeList.render() method can be considered polymorphic. The method iteratively invokes render() on anonymous instances. All it cares about is the render() interface.
Labels:
django
,
nodelist
,
python
,
template
,
templateengine
,
webframework
Friday, January 9, 2009
Template considerations in ECP
Recently, the ECP development team has started to question the validity of building HTML templates that essentially do the same thing as the ECP RESTful API. Of course we need to build HTML templates, it is a web application after all. What the discussion here comes down to is the age old question of separation of concerns. How much logic should be contained in the template if any? Kid templates, for example, offer several means of implementing logic within the template. I think the ability to construct page elements iteratively within the template itself is a powerful concept and solves a very basic problem. Iterating through a set and building elements does not necessarily mean you are not carefully considering the separation of concerns idea. Who knows, the set being iterated through may be data that was specifically built for the template. That is the idealistic case but it is also hard to come by in software development given the common time constraints today.
Anyway, back to the problem of how to build a web interface without building gigantic HTML templates. One may think that since in the case of ECP the problem is simple; there already exists a RESTful API, why not use some javascript library such as jQuery to build the entire HTML content based on the results of querying the RESTful API? If it were that simple, I think everyone would build things that way would they not? I mean, it would make sense to build a web application with a fancy GUI interface that is inherently flexible enough to support any client that was built to use it. Without the RESTful API, all you have is the stand-alone server with many browsers executing the same client code connecting to the server. Not a whole lot of diversity in this situation. As far as I'm concerned, the days of writing HTML parsers to fit a particular client purpose are over. The demands have risen and for good reason.
The moral here, if there is one, is the bottom line is the software does what it is supposed to do and that clients can interact with it somehow. If it is only a browser that needs to communicate with your application, build HTML templates. If there are only custom-built clients using your software, use JSON/XML. If you can do both, do it. That is what the current boat in which ECP resides. In the future, hopefully we can develop some javascript that is sophisticated enough to build the entire interface using the RESTful API data. I think this is a very real possibility.
Anyway, back to the problem of how to build a web interface without building gigantic HTML templates. One may think that since in the case of ECP the problem is simple; there already exists a RESTful API, why not use some javascript library such as jQuery to build the entire HTML content based on the results of querying the RESTful API? If it were that simple, I think everyone would build things that way would they not? I mean, it would make sense to build a web application with a fancy GUI interface that is inherently flexible enough to support any client that was built to use it. Without the RESTful API, all you have is the stand-alone server with many browsers executing the same client code connecting to the server. Not a whole lot of diversity in this situation. As far as I'm concerned, the days of writing HTML parsers to fit a particular client purpose are over. The demands have risen and for good reason.
The moral here, if there is one, is the bottom line is the software does what it is supposed to do and that clients can interact with it somehow. If it is only a browser that needs to communicate with your application, build HTML templates. If there are only custom-built clients using your software, use JSON/XML. If you can do both, do it. That is what the current boat in which ECP resides. In the future, hopefully we can develop some javascript that is sophisticated enough to build the entire interface using the RESTful API data. I think this is a very real possibility.
Subscribe to:
Posts
(
Atom
)