How to use a base.html for default Wagtail Page instance? - django

Wagtail starts new projects with a single welcome template. However, this template does not inherit from any parent template, such as a base.html. In our project, we have previously defined a base.html containing global HTML tags and CSS/JavaScript includes.
How can we tell the default Wagtail Page model to display in a template that extends base.html?

To clarify, there are two possible setups, depending on how you create your project:
If you start a new project from scratch with wagtail start myproject, the initial migrations (which exist partly within Wagtail itself, and partly within the project template) will set you up with a HomePage model and an initial homepage. The template for this page type lives at home/templates/home_page.html, and is already set up to inherit from a base template (which lives at myproject/templates/base.html).
If you follow the documentation for integrating Wagtail into an existing Django project, the initial migrations (which in this case are entirely within Wagtail) will give you an initial page of type wagtailcore.Page. You're not really expected to use this page type directly (not least because it has no fields beyond the title, and no way of adding new ones) - it's only done this way because there are no "proper" page models set up yet, and there needs to be something as the initial state of the page tree. The idea is that once you've set up at least one page model within your app, you can create your real homepage, point the Site record at it (in Settings -> Sites), and delete the initial stub one.
Nevertheless, if you really want to give wagtailcore.Page a full-fledged template with a base template, you could create a template file inside one of your project's apps at the path templates/wagtailcore/page.html. As long as the app in question is above 'wagtail.core' in the INSTALLED_APPS list, this will override the barebones template supplied by Wagtail.

{% extends "base.html" %}
Add that to your template, it will extend anything in the base.
If your base template has blocks in it, you use the same syntax
{% block content %}
This will appear wherever you have this same block in the base.html template
{% endblock %}
Wagtail is built on top of Django, you can read more about its templating language here: https://docs.djangoproject.com/en/3.0/ref/templates/language/

Related

How to add an html block across all pages (templates)?

I have a flask-admin app with quite a number of custom templates. I want to add an html block at the top of every page in the app. The obvious solution would be to add it to every template (and don't forget to add it to any new custom templates) but I hope there might be a better solution, to specify the html I want in a single place and have all future new templates automatically have it.
To simply insert HTML snippets into your templates you could use
{% include 'template_file.html' %}
To automatically get all new templates to use the HTML block try the jinja2 template inheritance which all of your templates would need to inherit from. Docs

Use the modified admin template only for one Image app

Django 3.0.6
For one model I need a modified admin site template.
Namely, I want to modify this template:
admin/includes/fieldset.html
I have copied the fieldset.html from Django package directory and placed it like this:
/my_project/image/templates/admin/includes/fieldset.html
Here image is my application. It is this application that needs a modified admin template.
The problem is that all other models also get this template. And the used template filters don't receive necessary params and explode.
Documentation: https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#set-up-your-projects-admin-template-directories
Well, I got confused and fail to organize the necessary directories structure.
How can I use the modified template only for one Image app?
You have a couple of issues. Firstly, only the following templates can be overridden per-app or per-model:
actions.html
app_index.html
change_form.html
change_form_object_tools.html
change_list.html
change_list_object_tools.html
change_list_results.html
date_hierarchy.html
delete_confirmation.html
object_history.html
pagination.html
popup_response.html
prepopulated_fields_js.html
search_form.html
submit_line.html
fieldset.html isn't in there, so you'll need to see if the including template(s) is in this list, and if it is, replace this template and use it to include your own version of fieldset.html.
Also, your location (slightly modified since can't override included templates per-app): /my_project/image/templates/admin/template.html isn't quite right. This will overwrite that template for every app. To do it per-app, you need a further subdirectory under admin:
/my_project/image/templates/admin/image/template.html
The reason for this is that templates don't really care about which app they're in, so the fact that the template lives in your image app doesn't mean anything to Django, the convention of putting them in your app's sub-directory is solely to avoid overriding templates that you don't intend to.

django cms [aldryn newsblog] replace template for plugin

I need to replace same plugin template on different subpages - e.g. on frontpage I need specific slider template for latest articles, in detail article I need small list, on search result without images etc.
[note: everything about aldryn newsblog app - I don't mean my own plugin!]
*(something like custom template per plugin instance)
How to replace it ? Extending template is not quite what I need - inheritance is from bottom - from lower subtemplate to base.html - but that plugin have hardcoded lower template.
Tons of IF block in template is irrational then we think in MVC.
*( like here Render Django-CMS plugins differently on different splaceholders/templates )
Or maybe just write custom template with using hardcoded including plugins ? But using django cms placeholder editor is very useful and it'll be better to keep working in that way :///
So, I create front.html base template for frontpage,
put some plugins to placeholders - and need to replace subtemplates for this plugins only in this front.html and keep subtemplates for that plugin in other places - this is main goal.
It will be the best, when django cms / aldryn newsblog provide option "custom template" per plugin instance :|
( like this one http://www.ilian.io/django-cms-plugins-with-selectable-template/ )
If I understand your question correctly (it's late here), you need a way to override plugin templates on a plugin instance basis because hacking django templates is not the way to go (I agree).
Django CMS does allow you to override plugin templates on an instance basis.
As shown in http://docs.django-cms.org/en/develop/how_to/custom_plugins.html?highlight=get_render_template#the-simplest-plugin
In your CMSPluginBase subclass add the following:
def get_render_template(self, context, instance, placeholder):
# criteria goes here
return 'sometemplate.html'
As far as how to know which template to render when (criteria), you can do a few things.
Use the page's reverse id:
page = instance.page
templates = {
'homepage': 'plugin_home.html',
'about': 'plugin_about.html',
'contact': 'plugin_contact.html',
}
return templates[plugin.page.reverse_id]
This approach has a few drawbacks:
Relies on plugin being bound to a page. (plugins can live outside of pages)
Can only work with pages that have reverse id set and reverse ids
are unique per page which means you would have to list reverse id
for every page you want to change template for.
Use a page extension to set a category per page:
Checkout http://docs.django-cms.org/en/develop/how_to/extending_page_title.html
With this approach you can then set some sort of category to multiple pages and so you can target multiple pages in one shot like so:
page = instance.page
extension = get_page_extension(page) # Check out docs for this
templates = {
'category_1': 'plugin_category_1.html',
'category_2': 'plugin_category_2.html',
'category_3': 'plugin_category_3.html',
}
return templates[extension.category.name]
Pros:
Can target multiple pages in one shot
Cons:
Relies on plugin being bound to a page.
A bit more complex
Use a template context variable:
In your templates, depending on how you're rendering your plugins, you can
provide a context variable like so:
{% with category='category_1' %}
{% placeholder 'content' %}
{% endwith %}
or
{% with category='category_1' %}
{% render_plugin yourplugin %}
{% endwith %}
Then in your get_render_template method you can access this context variable and do the following:
# Use .get() to provide fallback
category = context['category']
templates = {
'category_1': 'plugin_category_1.html',
'category_2': 'plugin_category_2.html',
'category_3': 'plugin_category_3.html',
}
return templates[category]
Pros:
No extra models.
Can target multiple pages in one shot.
Cons:
The only one I can think of is these random {% with %} in
templates.
I completely missed the newblog part, so in order to override the newsblog plugins or any plugin, just subclass the plugin class you want to override and unregister the original and then register yours, make sure yours has the same class name.
Maybe you can make the whole template logic above into a mixin to use throughout your project.
I've always wanted to give Zinnia a look, but I'm too far into working with NewsBlog on a site right now to do it (and blogs have already been posted and whatnot). You can always just add a few extra placeholders in the template (it's not the most efficient looking thing ever, but it's no load on the framework if you add a placeholder and leave it blank), that way they aren't static, and then you can put whatever plugins you want to inside of them. You can customize each component in NewsBlog pretty easily by just adding whatever you want in the structure mode. Things get trickier when it comes to having multiple blogs that act differently, but even then, as long as you're not adding components into the static placeholders provided by NewsBlog (or as I so elegantly learned it, "don't put the stuff in the blocky-things with the pins next to them), you can create different namespace for the different blogs (either in the admin, under "Configs" in the NewsBlog section, or when creating a new page and hooking it to the NewsBlog app), and you can have different templates on different blogs.
EDIT: This is a really excellent resource for touching up NewBlog without throwing the baby out with the bathwater (after three months of learning DjangoCMS, I'm still finding myself referencing it for fine-tuning pieces of NewsBlog, and to refresh my grasp on templatetags and other things that are overwhelming and have quickly left my brain along the way): https://www.django-cms.org/en/blog/2016/02/16/build-a-website-without-knowing-python-django-part-two/
*I linked to part two, as the first part deals with how to initially setup a project, and I assumed it probably wasn't relevant. Then again, if you're using Aldryn, there are some useful bits in there that can extrapolate if you're having trouble with customizing the boilerplate (or other things you'd like to configure that an Aldryn setup handles for you -- which is super awesome most of the times, but when it's not super awesome, it's usually super frustrating :)

Change django template search path depending on request

For my application I want to serve a different base.html (and other templates and static files) for visitors and for admins: visitors will see a customized themed frontend, admins will see the editor interface (not related to the django admin interface). Some templates / resources will be shared between the two frontends.
I know I can do this by having separate settings.py configurations and include different template paths in each of them through a django app, but that would also mean I have to run two instances of the app. I'd rather serve both frontends from a single instance (or pool of workers).
Is there a way to dynamically add extra folders to the Django search path? That should suit my needs: if the user comes through the visitor domain, search the added path first and then the defaults, else just use the default template search path.
This is exactly why I've created django_layers
It's inspired by the Plone skinning/layer system where you can switch skins and have the framework search different layers for templates, staticfiles, and so on. I was missing something similar in Django where, like you, the only option I could find was inheritance or distinct INSTALLED_APPS configurations.
It turns out it's also very suitable for other use-cases such as A/B testing.
The packages is relatively new, let me know if it works for you or if you have issues if you decide to use it.
You can leverage template inheritance for this purpose, especially the {% extends %} template tag, which can accept variables instead of literal strings.
Example:
In your child templates make them extend unknown base template like this:
{% extends BASE_SITE_TEMPLATE %}
{% block page_head %}
<!-- Custom per-page static files may be defined here -->
{% endblock %}
{% block page_content %}
...
{% endblock %}
And then write a template context processor that will pass the BASE_SITE_TEMPLATE variable based on your custom conditions to rendered templates:
def base_site_template(request):
# Here goes your conditions to select proper base template, for example
# by checking request.user permissions or some other logic.
...
return {'BASE_SITE_TEMPLATE': ...}
Of course You will need to define various base templates, like base_site_user.html, base_site_editor.html, base_site_admin.html.
This method doesn't require you to change any of your views, just child templates, so I think it's one of the simplest methods to do what You want.

Subrequests in Django templates

I'm working on my first Django project and have my templates setup with a base that all the others extend. In that base I want to have some user-specific navigation which means loading some values from the database to build the contents of a drop down menu. However I don't want to have to do this inside each view. Coming from Symfony2/Twig I would normally do this using a sub-request where I tell the template to render a view and that will use it's own template. Using syntax like:
{% render 'Bundle:Controller:action' with {} %}
How would I accomplish this same thing with Django? I've read over the docs a couple of times but can't find any way to do this.
You have two approaches:
(better)
- add the code to base.html (the one you're always extending) and only override it when you need to.
or
(worse)
- in every template use {% include %} to include your menus.html template.
Update: re-reading your question: you could modify the request in context-processor so your base.html would then have this information.
Custom template tags are what you want.