I have a Django application running using Django CMS.
I am trying to make one specific submenu not clickable.
The menu is like this:
item1|item2|item3
sub_item3
sub_item3
What I want is that everything is clickable except for "item3" menu item.
How can I achieve this knowing item3 is a Django CMS page itself as are each of its children pages?
The idea behind this is to prevent that the user sees an empty page when he clicks on the top "item3" menuitem.
Here is how I have done this to keep it from linking anywhere:
{% load cms_tags menu_tags %}
{% for child in children %}
<li>
{% if child.is_leaf_node %}{{ child.get_menu_title }}{% else %}{{ child.get_menu_title }}{% endif %}
{% if child.children %}
<ul>
{% show_menu 0 100 100 100 "menu/top-menu.html" "" "" child %}
</ul>
{% endif %}
</li>
{% endfor %}
In your case you may want a class with some css like this from Disable a link using css
.active {
pointer-events: none;
cursor: default;
}
Ok I fixed it with a mix of the previous answer and these links https://groups.google.com/forum/?fromgroups=#!topic/django-cms/aS2Ew2mf8XY and the docs https://django-cms.readthedocs.org/en/2.4.0/extending_cms/app_integration.html#how-it-works (navigation modifiers).
from menus.base import Modifier
from menus.menu_pool import menu_pool
class MyMode(Modifier):
"""
"""
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
if post_cut:
return nodes
for node in nodes:
if node.title == u'Page not clickable':
node.no_click = True
return nodes
menu_pool.register_modifier(MyMode)
With this template
% load cms_tags menu_tags %}
{% for child in children %}
<li>
{% if not child.no_click %}{{ child.get_menu_title }}{% else %}{{ child.get_menu_title }}{% endif %}
{% if child.children %}
<ul>
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% endif %}
</li>
{% endfor %}
And in my main template (base.html) I add the menu with
{% show_menu 0 100 100 100 "menu.html" %}
Related
Following the treebeard docs api example, I created an annotated_list of my tree using get_annotated_list(parent=None, max_depth=None) with parent=<my root node>. I pass this to my template and using the example they attribute in the docs to Alexey Kinyov, I am able to successfully display my tree using
{% for item, info in annotated_list %}
{% if info.open %}
<ul><li>
{% else %}
</li><li>
{% endif %}
{{ item }}
{% for close in info.close %}
</li></ul>
{% endfor %}
{% endfor %}
What I would like though is to be able to give these nested lists dropdown features. Borrowing from this standard example on w3schools, I modified it to work with my annotated_list template variable and ended up with this:
<ul id="myUL">
<li><span class="caret">{{ annotated_list.0.0 }}</span>
{% for item, info in annotated_list|slice:"1:" %}
{% if info.open %}
<ul class="nested"><li>
{% else %}
</li><li>{% if item.get_children_count > 0 %}<span class="caret">
{% endif %}
{% endif %}
{{ item }}
{% if item.get_children_count > 0 %}</span>
{% endif %}
{% for close in info.close %}
</li></ul>
{% endfor %}
{% endfor %}
</li>
</ul>
My code almost works, but does not seem to display node children for left-most nodes and I can't figure out why.
Note: CSS & JS not included in question but needed to make the dropdown menu work (I'm just using the out-of-the-box CSS/JS used in that w3schools example)
The most likely reason is that there is a problem with the tree.
Run Model.find_problems() to confirm.
Model.fix_tree() can fix most of the common problems.
Note that the get_annotated_list_qs() function doesn't really work at all.
You can try this Code:
<ul id="myUL">
{% for item, info in annotated_list %}
{% if item.get_children_count > 0 %}
<li><span class="box">{{item}}</span><ul class="nested">
{% else %}
<li>{{item}}</li>
{% endif %}
{% for close in info.close %}
</ul>
{% endfor %}
{% endfor %}
</ul>
It worked for me.
To add some missing context:
views.py:
def tree(request):
annotated_list = Category.get_annotated_list()
# template_name = 'JsonDefine/tree.html'
context = {
'annotated_list': annotated_list
}
return render(request, 'JsonDefine/tree3.html',context)
urls.py
from django.urls import path
from . import views
app_name = 'MyApp'
urlpatterns = [
path('tree/', views.tree, name='tree'),
]
I want to add simple back/next pagination in my item detail view.
How can I do that ?
I have something like that in my template:
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
Back
{% endif %}
{% if page_obj.has_next %}
Next: {{ item.title }}
{% endif %}
</span>
</div>
{% endif %}
The main thing is that I want to do this in ItemDetailView, not in ItemListView, because in list view I have all items, and I just want to go between items in detail view.
Thanks a lot for help.
Can you give me an example how can i use Navigation Nodes?
Cannot find examples in documentation.
There is this {{ node }} but where is it coming from?
Particalarly i am intereisted in {{ node.is_leaf_node }}.
Each navigation node is simply a link/entry in your menu tree so they are generated from your page layout, for example:
- Home
- About
- Projects
- Project A
- Project B
- Contact
creates a menu with each page representing a node in the menu tree.
There's an example of them working in the default menu.html template (where child is a node in the menu):
{% load menu_tags %}
{% for child in children %}
<li class="{% if child.selected %}selected{% endif %}{% if child.ancestor %}ancestor{% endif %}{% if child.sibling %}sibling{% endif %}{% if child.descendant %}descendant{% endif %}">
{{ child.get_menu_title }}
{% if child.children %}
<ul>
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% endif %}
</li>
{% endfor %}
In base.html:
<div id="menu_shop">
<input name="search" placeholder="search">
<p>Category:</p>
{% load mptt_tags %}
<ul class="root">
{% recursetree nodes %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
</div>
in views:
def show_category_tree(request):
return render_to_response("base.html",
{'nodes': Category.tree.all()},
context_instance=RequestContext(request))
urls.py:
url(r'^category/', 'item.views.show_category_tree'),
url(r'^category/(?P<slug>[\w\-_]+)/$', 'item.views.by_category'),
How to display this in "by_category.html"
If I try(for example):
{% extends "base.html" %}
{% block content %}
{% for e in entries %}
<p><b>{{ e.name}}</b></p>
<p>{{ e.desc}}</p>
{% endfor %}
{% endblock %}
I have this error:
http://dpaste.com/810809/
{% extends "base.html" %} does not work. If I remove it, everything works.
You are seeing this error because your template context for the by_category does not include nodes.
The extends tag is related to the template, not the view. It makes your by_category.html template extend the base.html template, but it does not include the template context from any other view.
The easiest fix would be to add nodes to your template context in the by_category view.
def by_category(request, slug):
entries = Entry.objects.filter(...)
return render_to_response("base.html",
{'entries': entries,
'nodes': Category.tree.all()},
context_instance=RequestContext(request))
This would be repetitive if you want to display the nodes in lots of other views. If you want to include the nodes in all views, you may want to write a request context processor. If you want to include it in some but not all pages, then try writing a custom template tag.
I'm working on a project where there's some specific styling on a menu item which has nested children. The menu structure looks something like this
Home
|
About
|
Services
|_ web design
|_ social marketing
|_ traditional marketing
I'm using {% show_menu 0 100 100 100 "menu.html" %} in my template and I have the following inside my menu.html:
{% load menu_tags %}
{% for child in children %}
<li class="{% if child.selected %}active{% endif %}{% if child.sibling %}dropdown{% endif %}">
{{ child.get_menu_title }}
{% if child.children %}
<ul>
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% endif %}
</li>
{% endfor %}
I put {% if child.sibling %}dropdown{% endif %} in there to illustrate where I want the class to be added, but targeting it as a child.sibling is not the right way of doing it. Is there a way to target the specific dropdown like this {% if child.has_children %}dropdown{% endif %}?
Thanks
{% if child.children %}...{% endif %}