django-wiki: how to list all articles under root article - python

I am a newbie in Django and am currently building a site. I have downloaded django-wiki ver 0.4a3 to have a wiki app for my site. Everything works fine, out-of-the-box. But instead of showing the root article as the main page, how can I show a list of all articles under the root article, so users can just click on any child article to open up that article? At the moment, users have to click a menu option to browse up one level or to browse at the current level to have a listing of all articles at that given level. I find this rather tedious. I rather have an "Windows Explorer tree-and-branch-like" navigation, e.g.,
root
|_child 1
| |_child 1.1
| |_child 1.2
|
|_child 2
| |_child 2.1
| |_child 2.1.1
|
|_child 3
Please note I am asking how to get a list all of articles under the root article, not how to create a template to implement the tree-and-branch articles navigator. Once I know how to get a listing of all articles, I think I can implement the necessary HTML and CSS to have that kind of navigator. I appreciate any pointers.
P.S. I have previously tried the official django-wiki google support group, but I think the support there is dead and buried. My two questions there are neither answered, let alone read (I only get 1 view -- which is actually my view count).
Chris.

[Solved.]
Make a copy of article.html originally located at wiki/templates/wiki/ and place this copy in your own project's templates/wiki/ directory. At the place where you want to place the tree directory, add something like the following lines:
<!-- article.html -->
...
<h4>List of articles</h4>
<ul>
<!-- Need to get the first article (root) -->
{% url 'wiki:get' path=urlpath.root.path as rootpath %}
<li>
<a href="{{ rootpath }}">
{{ urlpath.root.article.current_revision.title }}
</a>
</li>
<!-- Now get all the descendent articles of the root -->
{% for child in urlpath.root.get_descendants %}
<!-- Don't list articles marked for deletion -->
{% if not child.is_deleted %}
{% with ''|center:child.level as range %}
{% for _ in range %}<ul>{% endfor %}
{% url 'wiki:get' path=child.path as childpath %}
<li>
<a href="{{ childpath }}">
{{ child.article.current_revision.title }}
</a>
</li>
{% for _ in range %}</ul>{% endfor %}
{% endwith %}
{% endif %}
{% endfor %}
</ul>
You can fancy up the code above. I am new in Django (and to using django-wiki), so this might not be the cleanest or most efficient way, but the above works as expected for me.
Advantage:
The list of articles are always updated, so any deleted articles are removed and inserted new articles are shown.
The tree-like hierarchy visually shows all the available articles and their relationships with one another. This visual depiction is far, far better than the default's which is hard to even know how many articles exist or how far deep articles are nested.
Disadvantage:
According to the django-wiki's source code, get_descendents method is an expensive call, but for my small site, I have not noticed any penalty hits (so far).

Assuming your structure is no more than 10 deep:
[article_list depth:10]
Put this in your root article.

Related

Lektor CMS : Can't get lektor-tags to work properly, The requested URL was not found on the server

I am trying to build a blog using lektor CMS, for that.. i needed a tags system, after searching i found a lektor plugin on lektor docs called lektor-tags
I followed every step on the docs, struggled a lot and even visited the github repo to see if is there anything else not included in the docs.
My problem is when i try to visit localhost:5000/{the_tag_name} say like localhost:5000/python i always get a 404 Not Found saying that
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
This is what i did so far:
Before using lektor-tags:
I changed the route for the blog posts to be /posts instead of /blog.
Added slug format to models/blog.ini in [children]
[children]
model = blog-post
order_by = pub_date, title
slug_format = {{ (this.pub_date|dateformat('YYYY/M/') if this.pub_date) ~ this._id }}
Created 3 posts, everything was working properly.
At this point i wanted to use a tags system so i chosen to use lektor-tags, what i did was:
Installation
lektor plugins add lektor-tags
Created configs/tags.ini with this config:
parent = /
url_path = {{ this.parent.url_path }}{{ tag }}
tags_field = tags
ignore_missing = true
template = tags.html
Created templates/tags.html with the following content:
{% extends "layout.html" %}
{% block title %}{{ this.title }}{% endblock %}
{% block body %}
<div class="container mt-3">
<b>Tag: {{ this.tag }}</b>
<b>Items:</b>
<ul>
{% for i in this.items %}
<li>{{ i._id }}</li>
{% else %}
<li><em>No items.</em></li>
{% endfor %}
</ul>
</div>
{% endblock %}
Edited models/blog-post.ini and added:
[fields.tags]
type = strings
In templates/blog-post.html i added the following to show links to the page that contain a list of all posts with the specific tag:
{% if this.tags %}
<ul>
{% for t in this.tags -%}
<li>
<a href="{{ ('/' ~ t.lower())|url }}">
All posts tagged {{ t }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
Finally i updated a post to contain some tags from the admin and made sure it's there in content.lr for that post. so i stopped the lektor dev server and run it again lektor servor with no errors to be present.
The links were there in the post for the tags but when i click and follow a link say for example for the python tag localhost:5000/python i get 404 Not Found. i am new to lektor. i'm wondering what i did wrong and how can i get this to work properly?
NB: Other plugins i used are lektor-minify, lektor-disqus-comments the docs for these plugins were straightforward and i didn't got confused, but when it comes to this specific plugin i were confused, struggling: the docs were not that great and explaining, i felt completely lost!
Update
I created a github repo containing the code and what i have done so far so you can easily replicate this.
Update 2
I managed to get this to work properly see my answer below, however now i'm wondering how to set the root as the parent in other words how to edit this expression :
<a href="{{ ('/posts#tag/' ~ t.lower())|url }}">
to generate a source path for each of the blog post's tags but using root as the parent.
As you can see i tried this :
<a href="{{ ('/' ~ t.lower())|url }}">
but this doesn't work properly.
It's worth mentioning that lektor uses jinja2 templating language.
So Basically it was me doing this wrong because i wanted to use the root as the parent in tags.ini like so :
parent = /
I ended up changing the expression '/blog#tag/' ~ t.lower() in blog-post.html to something like :
<a href="{{ ('/' ~ t.lower())|url }}">
making it not able to generate a source path for each of the blog post's tags
What i changed and worked was :
I chosen posts to be the parent, updated the configs/tags.ini to :
parent = /posts
url_path = {{ this.parent.url_path }}{{ tag }}
tags_field = tags
ignore_missing = true
template = tags.html
Updated templates/blog-post.html :
{% if this.tags %}
<ul>
{% for t in this.tags -%}
<li>
# '/posts#tag/' ~ t.lower() because i changed the route of blog to posts
<a href="{{ ('/posts#tag/' ~ t.lower())|url }}">
All posts tagged {{ t }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
After running lektor clean --yes then lekor server everything was working properly including the tags system.

Strategy for handling recursive template display in Django

I'm rewriting a family tree app in Django that I previously wrote in Laravel. There's an 'outline view' page where I start with the 'original families' at the top of the tree, and show an outline of their children, their children's families/kids, those kids' families/kids, etc.
First I've generated a big nested list with all the info (in the controller for laravel, and in views.py in my Django rewrite). Then I give that list to a couple of views to display the lists for each original family. (Code included below)
Testing the logic a couple levels at a time it works, but when I let it call recursively and load my outline page, it gives me a recursion error: maximum recursion depth exceeded while calling a Python object.
Reading around, it sounds like python has a known limitation that it doesn't handle tail recursion, and I saw some posts saying that showing recursive views isn't good practice in Django.
Update: I've also started down the road of making a management command to generate an html page for this (that I can just show statically, and regenerate when I add new people), and that way I do avoid the recursion error. I'll do a bit more debugging with the original views to see what I can find out about where/when I reach the error (only for one particular branch or family, etc?) in case there's something I can fix in the way I generate the list.
Is there a better way to approach this problem in Django?
outline_whole.html:
{% for entry in results %}
{% get_class entry as object_type %}
{% include chunk_view %}
{% endfor %}
outline_family_chunk.html: (aka chunk_view, passed into the context)
{% get_class entry as object_type %}
<ul>
{% if object_type == 'Family' %}
{{ entry.display_name }}
{% elif object_type == 'Person' %}
<li>{% include "familytree/person_name_link.html" with person=entry %}</li>
{% elif object_type == 'list' %}
<ul>
{% for item in entry %}
{% include chunk_view with entry=item %}
{% endfor %}
</ul>
{% endif %}
</ul>
Example of the list it's working through- it gives a family with its children, then a list for the next family (where one of the original children was a parent):
[<Family: The Skywalker family (Anakin & Padme)>, <Person: Luke Skywalker>, <Person: Leia Skywalker>,[<Family: The Solo family >, <Person: Kylo Ren>]]
So without data it's hard to see where the problem is, but the obvious candidate is:
this_user -> Branch -> descendants[] --\
^ | <- has this_user
|______<___________<__________<______/
So when rendering a person, you render his branch, for which you call get_descendants and then from what I can tell, this could include the top-level user and we go round and round.
But like I said, it's a guess.

How do I choose a category page to be the home page for a Pelican site?

I would like the visitors to my site to land on a category page, not on the default index.html. I want them to see the articles in the News categories before anything else.
Maybe is there a way to tell Pelican to output category/news to index.html? I know this would be possible with normal handwritten pages using the save_as field, but how can I do it with an automatic page generated by Pelican?
Your homepage, the index.html file, is just another template from the DIRECT_TEMPLATES list. It'll depend on your theme exactly how it is generated, but you can always override specific templates locally, or you can create a new template for your homepage to replace it (and optionally redirect the original index.html generated page to a different location).
Either way, you can then generate a section that shows the articles from a single category. All template pages are given the same basic variables, which includes the articles list, as well as a categories list with (Category, list_of_articles) tuples.
The easiest way to get all articles for a single, specific category is to filter the articles list directly with the Jinja2 selectattr filter. selectattr('category', '==', categoryname) is matched both against the category name or the slug (whatever you set categoryname to is converted to a slug for you). So if your category is named News, then both 'News' or 'news' works:
<h2>News:</h2>
<ol id="posts-list" class="hfeed">
{% for article in articles | selectattr('category', '==', 'news') %}
<li><article class="hentry">
<header>
<h1><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark"
title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h1>
</header>
<div class="entry-content">
{% include 'article_infos.html' %}
{{ article.summary }}
<a class="readmore" href="{{ SITEURL }}/{{ article.url }}">read more</a>
{% include 'comments.html' %}
</div><!-- /.entry-content -->
</article></li>
{% endfor %}
</ol>
The above reuses the simple theme article markup. You may want to limit the number of news articles; in that case use the batch(size) filter together with first:
<h2>News:</h2>
<ol id="posts-list" class="hfeed">
{% for article in articles | selectattr('category', '==', 'news') | batch(5) | first %}
<!-- render article, etc. -->
The above takes the first 5 articles with News as the category.
Since the basic theme reuses the index.html template for all of the individual archive pages too (for each category, author or tag page), I'd not override the index direct template here. Instead, I'd create a new homepage template (in the pages directory) and write that to index.html and. You need to add the template in the TEMPLATE_PAGES dictionary, where your template pages should live in a separate directory that is configured not to be treated as articles or pages.
Create a new directory for template pages in your content directory; you'll need to make sure Pelican doesn't try to treat files there as articles, so add it to the ARTICLE_EXCLUDES list. So if all your Pelican your content lives in content/, and you have a file homepage.html in the directory output/templates/, you'd use:
ARTICLE_EXCLUDES = ['templates']
TEMPLATE_PAGES = {
'templates/homepage.html': 'index.html',
}
This will overwrite the default index.html generated for articles, there is no need to remove anything from DIRECT_TEMPLATES but you could do so to avoid generating a file you never keep.
The homepage.html template can make full use of any existing templates in the theme, so you can just extend base.html that most themes will have defined:
{% extends "base.html" %}
{% block content %}
<section id="content">
<h2>Recent news:</h2>
<ol>
{% for article in articles | selectattr('category', 'equalto', 'news') | batch(5) | first %}
<!-- markup for each news item -->
{% endfor %}
</ol>
</section><!-- /#content -->
{% endblock content %}
Instead of overwriting the default index, you can also set INDEX_SAVE_AS to direct the original index.html file elsewhere:
ARTICLE_EXCLUDES = ['templates']
TEMPLATE_PAGES = {
'pages/homepage.html': 'index.html',
}
# move the original article index elsewhere:
INDEX_SAVE_AS = 'all_articles.html'
If you use a theme that doesn't reuse the index.html template for more pages or you want to try to make the template work for in those contexts anyway, then you can override the template used for index instead. To override the default index.html from your theme, create a local directory (overrides perhaps) to put your local version into, then add that directory to the THEME_TEMPLATES_OVERRIDES list in your configuration:
THEME_TEMPLATES_OVERRIDES = ['overrides']
Now when Pelican tries to load the index.html template to render the index direct template, it'll look for overrides/index.html first. So in overrides/ add your own index.html:
{% extends "base.html" %}
{% block content %}
<section id="content">
<!-- put your desired content here -->
</section><!-- /#content -->
{% endblock content %}
A word on pagination: all templates, except for the special per-archive-type pages (categories, authors, tags, periods), are paginated on the full articles list, this isn't something that is further configurable. This means you can't paginate a homepage on a single category of articles.
This means that if you override the index.html template and removed the full article listing, then you may want to remove index from the PAGINATED_TEMPLATES dictionary so it isn't re-generated multiple times to match your article list.

Introduction pages for categories in Pelican

I would like to build my personal web pages in Pelican, but I am missing one functionality. I would love to have an introductory page for some/all categories on the pages.
For example - I would like to build a page for my grant project, where posts are related to activities and/or published papers, but I would also like a single page saying something about the grant project and keep this page as the title page of this category.
Is this possible (easily) in Pelican framework? If not, can you suggest better static pages framework that works in combination Markdown+Python?
This is actually very easy with pelican. The plugin Auto Pages defines three extra content folders: One for authors, one for categories and one for tags.
Say you, John Smith, wanted to have extra information about your person when clicking on your name. Then, you would add a file called authors/john-smith{.rst|.md} with this extra information. No HTML, but only the contents you want to provide about your person. These contents are then read in, transformed and presented to the template engine as author.page.
Now it is about your templates to also use this variable.
In my theme, I simply modified theme/templates/author.html to not show the combination of "featured article" and "other articles" related to my author, but to show author.page.content and "all articles" related to my author instead.
Short extract of my theme/templates/author.html:
<aside id="featured" class="body">
<article>
<h1 class="entry-title">{{ author }}</h1>
{{ author.page.content }}
</article>
</aside>
<section id="content" class="body">
<!-- removed the apostrophe for SO highlighting reasons-->
<h1>Authors articles</h1>
<hr/>
<ol id="posts-list" class="hfeed" start="{{ articles_paginator.per_page - 1}}">
{% for article in articles_page.object_list %}
<li><article class="hentry">
<header>
<h1><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark"
title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h1>
</header>
{% include 'article_infos.html' %}
{{ article.summary }}
<a class="readmore" href="{{ SITEURL }}/{{ article.url }}">read more</a>
{% include 'comments.html' %}
</article></li>
{% endfor %}
</ol>
{% if articles_page.has_other_pages() %}
{% include 'pagination.html' %}
{% endif %}
</section>
You can do the exact same thing for categories and tags using the procedure described above. For the template, just use the existing index.html and adapt it to your needs.

How to add pages to navigation on Pelican?

I know this may not be a very smart question, but it really bother me for a while.
I am using Pelican for site generating, with theme SoMA/SoMA2. I am adding a folder under content and some pages inside. This should appear on the navigation according to the Tutorial, but didn't.
I tried with default theme (in quickstart) and it works. Does it mean SoMA/SoMA2 don't support personalized navigation? Any ways I can do with it?
Thanks.
Your intuition is correct: the SoMA/SoMA2 themes do not currently add pages to the navigation menu. You can see this by comparing the notmyidea base template with the SoMA base template. The relevant code is:
{% if DISPLAY_PAGES_ON_MENU -%}
{% for pg in PAGES %}
<li{% if pg == page %} class="active"{% endif %}>{{ pg.title }}</li>
{% endfor %}
{% endif %}
I can't guarantee that will be entirely sufficient, of course, since I haven't fully examined how SoMA implements its navigation, CSS, et cetera. But perhaps this might point you in the right direction.

Categories

Resources