1

When inside a jinja template:

  1. How is the string, provided to {%extends xxx_string%} and {% include xxx_string%}, resolved?
  2. Is this relative to actual filesystem, or a generated namespace (such as when using the Flask.url_for function)?

Ultimately, I would like to use relative imports when inside my templates (I don't want to have to update filesystem locations INSIDE each and every template, with respect to the Blueprint). I would like to be able to :

  1. Store the actual Blueprint package and its nested static/template resources under an arbitrary filesystem path. ('/bob/projects/2013_07/marketanalysis')
  2. Within the python Blueprint package, define a separate 'slugname' to reference the blueprint instance and all of its resource. Register this slugname on the application for global references. (without global name collisions or race-conditions)
  3. Have generic view functions that provide 'cookie-cutter' layouts, depending on how the blueprint is being used (headlines, cover, intro, fullstory, citations)
  4. Internally, within the filesystem of the blueprint package, use relative pathnames when resolving extends()/include() inside templates (akin to url_for shortcuts when referencing relative blueprint views).

The idea is that when the blueprint package is bundled with all of its resources, it has no idea where it will be deployed, and may be relocated several times under different slug-names. The python interface should be the same for every "bundle", but the html content, css, javascript, and images/downloads will be unique for each bundle.


I have sharpened the question quite a bit. I think this is as far as it should go on this thread.

user2097818
  • 1,821
  • 3
  • 16
  • 34

3 Answers3

0

Using folders instead of prefixes makes it a bit more clean in my opinion. Example application structure:

yourapplication
|- bp143
   |- templates
      |- bp143
         |- index.jinja
         |- quiz.jinja
         |- context.jinja
|- templates
   |- base.jinja
   |- index.jinja
   |- bp143
      |- context.jinja

With the above structure you can refer to templates as follows:

base.jinja --> comes from the application package
index.jinja --> comes from the application package
bp143/index.jinja --> comes from the blueprint
bp143/context.jinja --> comes from the application package (the app overrides the template of the same name in the blueprint)
Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • that does help a bit, but I still must make references to those dirty paths from within the templates on includes/imports. I guess I was hoping I could just move folders around on the filesystem, and they would just *plug* into their new location with no further effort. – user2097818 Jul 26 '13 at 05:44
0

Explicitly load templates using... (not tested)

@blueprint.route('/summarize_article')
def summarize():
    fd = blueprint.open_resource('/blueprint/relative/pathid/section/introductions.jinja')    
    relative_ctx['article_intro'] = flask.render_template_string(fd.read(), **context)

    fd = blueprint.open_resource('/blueprint/relative/pathid/section/citations.jinja')    
    relative_ctx['article_citations'] = flask.render_template_string(fd.read(), **context)

    fd = blueprint.open_resource('/blueprint/relative/pathid/summarized_layout.jinja')
    return flask.render_template_string(fd.read(), **relative_ctx)

Manually load these templates as needed for each view. Im sure this could be cleaned up for multiple views, but I believe this is the intended behavior.

I am not sure if you can {% extend context_kword_key %}, but it should work for embedded includes()/imports().

user2097818
  • 1,821
  • 3
  • 16
  • 34
0

It seems the most appropriate solution for my "resource bundling" should be handled with Jinja loaders (see Jinja Docs on Loaders). Right away, jinja2.PackageLoader, jinja2.PrefixLoader, and jinja2.DictLoader seem like they could be fun.

The accepted answer for this Similar Thread gives an idea of how Loaders are handled in Flask. For the most part, we can stay out of the default application-level DispatchingJinjaLoader.

By default, I believe a Blueprint will end up with its self.jinja_loader to ...

jinja2.FileSystemLoader(os.path.join(self.root_path,
                                     self.template_folder)) 

This help us to understand how simple the default resolution algorithm is, and how easily we can extend Blueprint specific functions. A clever combination of Subclassed/Custom Loaders will let us create smarter Loaders, and allow us to sneak in a few magics that help us cheat.

The real power will come from overriding CustomBaseLoader.list_templates() and a quick little ProxyLoader hooked into the application's DispatcherJinjaLoader that will have priority over normal lookups.

Community
  • 1
  • 1
user2097818
  • 1,821
  • 3
  • 16
  • 34