I need a subnavigation on my pages. I inherit from base.html where the main navigation is located, but I don't know how to make a subnavigation which differs from page to page.
I've thought about making a template tag in which I can specify items to the subnavigation in each template file, and only output the subnavigation if any subnavigation items are specified. How do others do it?
Why can't you have a separate block for subnavigation and override that block in child templates?
base.html
Calls
Messages
{% block subnav %}
{% endblock %}
calls.html
{% extends "base.html" %}
{% block subnav %}
Outbound calls
Inbound calls
{% endblock %}
messages.html
{% extends "base.html" %}
{% block subnav %}
Sent messages
Recieved messages
{% endblock %}
A simple way to implement such could be to create a templatetag that takes an argument, for example the unique id or slug of the current page in the page tree.
E.g.
#register.simple_tag
def subnavigation_for_page(request, page_id, *args, **kwargs):
qs = Page.objects.filter(is_active=True)
current_page = qs.get(id=page_id)
sub_navigation = list()
for page in qs.filter(level__gt=current_page.level):
if page.level > current_page.level:
sub_navigation.append(page)
return sub_navigation
You could extend the example to return the rendered navigation as html or use the 'as' node to return a variable and define the html within the template itself.
Package that might be of interest:
django-mptt
Related
When using HTMX framework with Python Flask, you have to be able to:
serve a request as a HTML fragment if it's done by HTMX (via AJAX)
server a request as a full page if it's done by the user (e.g. entered directly in the browser URL bar)
See Single-page-application with fixed header/footer with HTMX, with browsing URL history or Allow Manual Page Reloading
for more details.
How to do this with the Flask template system?
from flask import Flask, render_template, request
app = Flask("")
#app.route('/pages/<path>')
def main(path):
htmx_request = request.headers.get('HX-Request') is not None
return render_template(path + '.html', fullpage=not htmx_request)
app.run()
What's the standard way to output a full page (based on a parent template pagelayout.html):
{% extends "pagelayout.html" %}
{% block container %}
<button>Click me</button>
{% endblock %}
if fullpage is True, and just a HTML fragment:
<button>Click me</button>
if it is False?
This solution based on that we can use a dynamic variable when extending a base template. So depending on the type or the request, we use the full base template or a minimal base template that returns only our fragment's content.
Lets call our base template for fragments base-fragments.html:
{% block container %}
{% endblock %}
It's just returns the main block's content, nothing else. At the view function we have a new template variable baselayout, that contains the name of the base template depending on the request's type (originating from HTMX or not):
#app.route('/pages/<path>')
def main(path):
htmx_request = request.headers.get('HX-Request') is not None
baselayout = 'base-fragments.html' if htmx_request else 'pagelayout.html'
return render_template(path + '.html', baselayout=baselayout)
And in the page template, we use this baselayout variable at the extends:
{% extends baselayout %}
{% block container %}
<button>Click me</button>
{% endblock %}
As pointed in the section Null-Default Fallback of Jinja documentation, the extends tag can actually come in an if statement:
Jinja supports dynamic inheritance and does not distinguish between parent and child template as long as no extends tag is visited. While this leads to the surprising behavior that everything before the first extends tag including whitespace is printed out instead of being ignored, it can be used for a neat trick.
Usually child templates extend from one template that adds a basic HTML skeleton. However it’s possible to put the extends tag into an if tag to only extend from the layout template if the standalone variable evaluates to false which it does per default if it’s not defined. Additionally a very basic skeleton is added to the file so that if it’s indeed rendered with standalone set to True a very basic HTML skeleton is added:
{% if not standalone %}{% extends 'default.html' %}{% endif -%}
<!DOCTYPE html>
<title>{% block title %}The Page Title{% endblock %}</title>
<link rel="stylesheet" href="style.css" type="text/css">
{% block body %}
<p>This is the page body.</p>
{% endblock %}
Source: https://jinja.palletsprojects.com/en/3.0.x/tricks/#null-default-fallback
So, your requirement could be fulfilled doing:
{% if not fullpage %}{% extends 'pagelayout.html' %}{% endif -%}
{% block container -%}
<button>Click me</button>
{%- endblock %}
I made a single-page site in static HTML with shiny screen-height divs, and a smooth scrolling function from a navbar. The website is expected to have a mixture of simple body text, a few images, and a card-deck. It all worked nicely and I was happy.
While I have used wagtail for very simple websites in the past, I cannot work out a way of making a single page site where the home page goes at the top followed by all the child pages in order. Is this possible with Wagtail's page models?
I've done something like this a while ago by rendering subpages of my HomePage class as section on this HomePage. There was some minor customization at various places involved (see below). Perhaps the hardest part was rewriting the page-urls of the "section pages" to point to the HomePage and the correct anchor on this HomePage (see below get_url_parts).
I've recycled the wagtail page class build-in in_menu to generate a navbar with/to the relevant sections.
While I've been trying to catch everything, I hope nothing relevant has slipped my mind...
Code
models/pages.py
class HomePage(Page):
"""
We only have one frontend page, on which we render child pages as subsections.
"""
parent_page_types = [
'wagtailcore.Page',
]
# The following page types (here named "sections") are standard wagtail
# page models, but rendered on this HomePage.
subpage_types = [
'TextSection',
'WhereSection',
'ContactSection',
...
]
# fields...
# panels...
def get_subsections(self):
"""
Return page queryset with sections to render on the HomePage.
"""
return (
self
.get_children()
.specific()
.live()
.public()
)
def get_context(self, request):
context = super().get_context(request)
context['subsections'] = self.get_subsections()
context['nav_sections'] = self.get_subsections().in_menu()
return context
models/sections.py
class BaseSection(models.Model):
"""
BaseSection abstract base class. All HomePage sections should inherit
from this class.
"""
parent_page_types = ['HomePage']
subpage_types = []
fields...
panels...
class Meta:
abstract = True
def get_url_parts(self, request=None, *args, **kwargs):
"""
Customising URL patterns for a page model
http://docs.wagtail.io/en/latest/topics/pages.html#customising-url-patterns-for-a-page-model
Rewrite page path to corresponding anchor of this section on the
containing page.
"""
url_parts = super().get_url_parts(request=request)
if url_parts is None:
return None
else:
site_id, root_url, page_path = url_parts
_cust_page_path = '#section-{}'.format(page_path.replace('/', ''))
return (site_id, root_url, _cust_page_path)
class TextSection(BaseSection, Page):
template = 'sections/text_section.html'
body = RichTextField()
content_panels = BaseSection.content_panels + [
FieldPanel('body'),
]
class FooSection(BaseSection, Page):
...
The rest is done via the template layer: looping over all subsection on the homepage:
# templates/home_page.html
{% extends 'base.html' %}
{% block navbar %}
{% include 'includes/navbar.html' %}
{% endblock navbar %}
{% block page_content %}
{% for subsection in subsections.all %}
{% with subsection.specific as subsection %}
{% include subsection.template with subsection=subsection %}
{% endwith %}
{% endfor %}
{% endblock %}
# templates/includes/navbar.html
{% load wagtailroutablepage_tags %}
<nav>
{% for item in nav_sections %}
<a
href="{% if not is_homepage %}{% routablepageurl page 'homepage' %}{% endif %}#section-{{ item.slug }}"
>
{{ item.title }}
</a>
{% endfor %}
</nav>
# templates/sections/section_base.html
<section id="section-{{ subsection.slug }}" class="{{ subsection.content_type|slugify }}">
{{ subsection.title }}
{% block content %}
{% endblock content %}
</section>
# templates/sections/text_section.html
{% extends 'sections/section_base.html' %}
{% block content %}
{{ subsection.body|richtext }}
{% endblock content %}
If you're building one page using Django templates, you should be able to pass a list of pages to your template using the get_context() method.
If it's an SPA, you could use AJAX requests to fetch other pages data from the built-in Wagtail API. If it doesn't fully suit your needs, you could still build your own API with e.g. the Django Rest Framework.
I have a very basic template (basic_template.html), and want to fill in the with data formatted using another partial template. The basic_template.html might contain several things formatted using the partial template.
How should I structure the code in views.py?
The reason I am doing this is that later on the will be filled using Ajax. Am I doing this right?
You can do:
<div class="basic">
{% include "main/includes/subtemplate.html" %}
</div>
where subtemplate.html is another Django template. In this subtemplate.html you can put the HTML that would be obtained with Ajax.
You can also include the template multiple times:
<div class="basic">
{% for item in items %}
{% include "main/includes/subtemplate.html" %}
{% endfor %}
</div>
You can do this using a block. Blocks are a Django Template tag which will override sections of a template you extend. I've included an example below.
basic_template.html
<body>
{% block 'body' %}
{% endblock %}
</body>
template you want to include: (i.e. example.html)
{% extends 'basic_template.html' %}
{% block 'body' %}
/* HTML goes here */
{% endblock %}
views.py:
return render_to_response(template='example.html', context, context_instance)
Doing this will load basic_template.html, but replace everything inside of {% block 'body' %} {% endblock %} in basic_template.html with whatever is contained within {% block 'body' %} {% endblock %}.
You can read more about blocks and template inheritance in the Django Docs
There are mainly 2 ways (2 easy ones)
1:
In base html put
{% include "myapp/sub.html" %}
And just write html code inside your sub.html file
2:
https://docs.djangoproject.com/en/dev/ref/templates/language/#template-inheritance
I just wanted to add differences of extend and include.
Both template and include can use models inserted in current app.
Template is for global usage by your any app. Include is for use in certain apps.
For ex: you want to insert Image Slider to your homepage and about page but nowhere else. You can create Slider app with its own model for convenience and import its model and include in that pages.
If you used template for this example, you would create 2 templates one with slider and everything else other template have.
I am trying to create a single page with different content from different template in django so i can print it. Its kind of summary of different page
base.html - mainContent block is rendered inside this template
main.html - Need mainContent block from here
graph.html - Need mainContent block from here
charts.html - Need mainContent block from here
summary.html - Need content from main, graph, charts all together here (REQUIRE)
I have a base template which is extended on every page like this (It has navbar, footer and sidebar)
{% extends "base.html" %}
There is a block inside base template where graph, main, chart content is displayed. What i am trying to accomplish is to get the mainContent from those page and add it to new template called summary.html
Since every page is extending from base i am not sure how to do that? I tried using include but it will also include base for every page.
EDIT: I know i can separate the mainContent into its own separate files but i have lot of templates and was looking for any other solutions.
You could separate the content.
I guess you have something like this:
<!-- graph.html -->
{% extends "base.html" %}
{% block 'mainContent'%}
{# Your graphs html here #}
{% endblock %}
But you could put the graph html in a separate, let's say graph_template.html template and include it:
<!-- graph.html -->
{% extends "base.html" %}
{% block 'mainContent'%}
{% include 'graph_template.html' %}
{% endblock %}
And then in summary.html you can include graph_template.html.
I have a template that looks like this:
{% include "base/top.html" with context %}
{% include "base/nav.html" with context %}
<div id="content">
Stuff
{% block content %}{% endblock %}
</div>
{% include "base/bottom.html" with context %}
base/nav.html and base/bottom.html contain static content, but base/top.html contains a {% block title %}. So when I have a second template as that attempts to inherit from the first file like so:
{% extends firstfile.html %}
{% block title %}Imarealpage!{% endblock %}
{% block content %}Lorem ipsum dorem smitshm{% endblock %}
The {% block title %} section isn't rendered. How do ensure that it, and any other blocks in included files and defined in extended templates are rendered as they should be?
You're misunderstanding how {% include %} works. The {% include %} tag is not a pre-processor; it doesn't plop the included template's code directly into the including template before rendering. Instead, {% include %} fires off a new independent template render of the included template (just like as if you had rendered the included template directly from your own code), and then includes the rendered results into the rendering of the included template.
The implication of this is that included templates have a totally separate inheritance hierarchy from their including template. You can, for instance, have a base component.html template with some blocks in it, and then have e.g. foo-component.html which starts with {% extends "component.html" %} and fills in some blocks from component.html. And then you can have a layout.html that does {% include "foo-component.html" %}, and that will render foo-component.html, complete with its inheritance of component.html, and place the result into that spot in layout.html. But there is zero relationship between any blocks in layout.html and any blocks in component.html -- they are separate renders with separate block structures and inheritance hierarchies.