I'm building an application in Pyramid and utilizing Jinja2 templates and traversal routing. In order to wire my view-callables with the templates I am using, I want to be able to reference my templates using the webapp:templates prefix. As an example:
#view_config(name='about-us', renderer='webapp:templates/pages/about-us.html', context=Root)
def static_pages(context, request):
... //more code
This decouples where the templates live from whats using them. In order to make the above functional, though, I had to put this inside the __init__.py in my webapp root folder:
config.add_static_view(name='templates', path='webapp:templates', cache_max_age=3600)
The add_static_view() causes the webapp/templates folder to be referenced as webapp:template in other configurations. However, it also makes it viewable from a url such as http://0.0.0.0:6543/templates/<some template file>. Is there a way to achieve the former goal without allowing the latter visibility as a static page?
add_static_view() is not supposed to cause the webapp/templates folder to be referenced as webapp:template in other configurations, if it does that it's just due to a weird side-effect.
The package:path syntax works because Pyramid uses pkg_resources API to resolve the paths. Here are some details.
This means that, in your example, webapp should be a python package located somewhere your app can find it.
Related
The django template folder requires creating a subfolder with the name of the app which then contains the template files. Why is this necessary, when python manage.py collectstatic can infer this information while traversing all directories? It seems very redundant.
First of all, Django does not require this specific folder structure for templates to work, it is just a stablished pattern to do so. And, of course, it has a rationale, as pointed in the official doc:
Template namespacing
Now we might be able to get away with putting our templates directly
in polls/templates (rather than creating another polls subdirectory),
but it would actually be a bad idea. Django will choose the first
template it finds whose name matches, and if you had a template with
the same name in a different application, Django would be unable to
distinguish between them. We need to be able to point Django at the
right one, and the easiest way to ensure this is by namespacing them.
That is, by putting those templates inside another directory named for
the application itself.
You can reference to this question or that another for concrete cases.
In a nutshell, by following this pattern you can have your templates organized in 2 groups:
templates related to your specific site or project can live inside the directory pointed by the TEMPLATES['DIRS'] setting;
templates related to a specific app, that could be served as is if you make your app pluggable, should live inside './appname/templates/appname/' (and TEMPLATES['APP_DIRS'] must be True). This way you avoid name conflicts between files inside this folder anf files from outside.
I use django and my application works, when I change the style.css the app changes etc.
However, I recently found out that I didn't define STATICFILES_DIR, I only defined
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
Which is only for collectstatic.
But now I'm wondering, how does django know where to look for the static files?
Specifically in the polls/static/polls directory?
Django will look for a directory named static in each of your apps by default. More on this later.
From the documentation:
Now we might be able to get away with putting our static files
directly in my_app/static/ (rather than creating another my_app
subdirectory), but it would actually be a bad idea. Django will use
the first static file it finds whose name matches, and if you had a
static file with the same name in a different application, Django
would be unable to distinguish between them.
The key part being
...Django will use the first static file it finds whose name matches...
There are Django libraries called "static file finders" that help with this process. You can configure them by modifying the installed apps in your Django configuration file.
According to the documentation, they're actually undocumented, because they are considered private. However, you can look at the source code for those "finders" on GitHub.
Django projects are composed of modules called apps. Each app contains some default files when you generate it. Although there is configuration, there's plenty of convention about Django too. For example, the views.py file. Another such convention is your app's static directories folder.
Your STATICFILES_DIR array allows you to add additional places for you to put your static files. This is useful, as you'll see when you prepare to deploy, because of the way Django handles static files in a real-world environment.
It's totally optional, but it's there to make your life easier later.
When inside a jinja template:
How is the string, provided to {%extends xxx_string%} and {% include xxx_string%}, resolved?
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 :
Store the actual Blueprint package and its nested static/template resources under an arbitrary filesystem path. ('/bob/projects/2013_07/marketanalysis')
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)
Have generic view functions that provide 'cookie-cutter' layouts, depending on how the blueprint is being used (headlines, cover, intro, fullstory, citations)
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.
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)
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().
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.
I am attempting to utilize Flask-Admin for an administrative interface to my web service.
I have it working, but the theme does not match what the rest of my site uses. The documentation here suggests that it is as simple as overriding the master template, but when I do that I end up with circular reference errors.
I have also tried on individual templates by copying the templates from the install directory to my application structure, but I cannot figure out the path they use. It is like it just defaults to the install directory, even if I have templates of the same name local to my flask app. From the docs: "You can override any used template in your Flask application by creating template with same name and relative path in your main templates directory."... yet I am not able to do that. Does it still expect admin/ in front of the templates?
Does anyone have an example? I basically need to override the bootstrap theme used, but some other customization could be nice. I'm new to flask, and python for that matter, so this may be quite simple...
You will still need to place your templates in the admin sub-folder of templates:
yourapp/
app.py
templates/
master.html # <-- This will not override admin/master
admin/
master.html # <-- This one, however, will :-)
Background:
I'm starting to use Django for the first time, which is also my first foray into web development. I just got stuck on the whole "serving static media" problem. After spending a while looking at all the documentation and StackOverflow questions, I think I understand how it's supposed to work (i.e. MEDIA_ROOT, MEDIA_URL, updating the urls file, etc).
My Question:
Ok, so here's the part I'm not sure about. Django applications are supposed to be "pluggable", i.e. I can move an application from one project to another. So, how should these applications bundle static media?
For example, let's say I have a "foo" application, which has templates that load some css/image files. Where am I supposed to put these files, so that they'll automatically get served once I include the application?
The only solution I see, is that installing an application has to include the extra step of copying its static media to some place on your own server that serves that media.
Is this the accepted way to do it? It includes an extra step, but maybe that's standard when dealing with web-dev (I'm new so I don't really know).
Also, if this is the way, is there a standard way to collect all my static media to make it easy to know what I need to serve? (I.e., is it standard to have a folder named "media" or something inside the app?).
Thanks,
Convention is to put static media in either media/appname/ or static/appname/ within the app (similar to templates).
For using apps in your project that come with media, I strongly recommend using django-staticfiles. It will automatically serve media (including media within apps) in development through a view that replaces django.views.static.serve, and it comes with a build_static management command that will copy media from all apps into a single directory for serving in production.
Update: django-staticfiles has become part of Django 1.3. It now expects app media to live in a "static/" subdirectory of the app, not "media/". And the management command is now "collectstatic."
The only app I know of that deals with this without any intervention is the rather wonderful django-debug-toolbar, though it's arguable that this isn't a great example, since it's an app specifically designed for debug mode only.
The way it deals with it is that it serves its media through Django itself - see the source for urls.py:
url(r'^%s/m/(.*)$' % _PREFIX, 'debug_toolbar.views.debug_media'),
In general, this is a bad idea (you don't want to serve static files through Django), per this comment from the documentation:
[Serving static files through Django] is inefficient and
insecure. Do not use this in a
production setting. Use this only for
development.
Obviously, the django-debug-toolbar is only used for development, so I think its method of deployment makes sense, but this is very much an exception.
In general, the best way I know to do it is to create symbolic links wherever your media is stored to the media inside your app code. For example, create a folder called media within your app, and then require users installing your app to either add a symbolic link from their media directory, or copy the whole thing.
i usually put apps media in ./apps/appname/static (my apps resides in an apps subfolder)
then i have something similar in the vhost in apache :
AliasMatch ^/apps/([^/]+)/static/(.*) /home/django/projectname/apps/$1/static/$2
<DirectoryMatch "^/home/django/projectname/apps/([^/]+)/static/*">
Order deny,allow
Options -Indexes
deny from all
Options +FollowSymLinks
<FilesMatch "\.(flv|gif|jpg|jpeg|png|ico|swf|js|css|pdf|txt|htm|html|json)$">
allow from all
</FilesMatch>
</DirectoryMatch>
i also have this in my urls.py for dev server (use only for debug) :
def statics_wrapper(request, **dict):
from django.views import static
return static.serve(request, dict['path'], document_root = os.path.join(settings.BASE_DIR, 'apps', dict['app'], 'static'), show_indexes=True)
urlpatterns += patterns('', (r'^apps/(?P<app>[^/]+)/static/(?P<path>.+)$', statics_wrapper))
this is very handy because statics url are simply mapped to filesystem, eg :
http://wwww.ecample.com/apps/calendar/static/js/calendar.js resides in [BASE_DIR]/apps/calendar/static/js/calendar.js
hope this helps