How to store nav menu urls in database? - django

I'm working on my first django app, and i have side nav menu like in twitter. To prevent the dozens of lines in my template like this
<ul class="nav d-flex flex-column">
<li class="nav-item align-self-start rounded-pill mb-3"><li>
<li class="nav-item align-self-start rounded-pill mb-3"><li>
...
<li class="nav-item align-self-start rounded-pill mb-3"><li>
</ul>
and for app extensibility i want to store nav menu in database to be able to loop over the menu items
<ul class="nav d-flex flex-column">
{% for item in menu %}
<li class="nav-item align-self-start rounded-pill mb-3"><li>
{% endfor %}
</ul>
But the problem is that i can't store direct urls for menu items in database, because several of them have dynamic urls e.g. profile page, which has 'slug:username/' pattern.
I've tried to store template tags in database like
{% url 'app_name:view_name' %}
but of course it doesn't work.
My current idea is to store in database namespaced url e.g. 'app_name:view_name' for static urls and 'request.user.get_absolute_url()' for pages which have username in urls.
The next step is to get QuerySet with menu items from database, loop over them and transform namespaces url with reverse (it works), but 'request.user.get_absolute_url()' is just a string and it doesn't work. Then make list of ditcs and pass it to context
menu = [{item1 attrs}, {item2 attrs},...,]
Is exists a better approach to solve my problem? And finally what i should do with dynamic urls?
UPD:
If we're dealing with menu items whose urls depend only on usernames i.e. only on User model, we can do smth like this (NavigationMenu - table model, url_link - column with following values: 'app_name:view_name' or 'get_absolute_url'):
menu = NavigationMenu.object.all()
for item in menu:
url_link = item.url_link
if ':' in item.url_link:
url = reverse(url_link)
else:
method = getattr(request.user, url_link)
url = method()
# then store all instance attrs in dict
But it seems that is not a good way to solve this.

The ideal approach to achieve this is to create a base.html in which you build this sidebar nav item, and then include that base.html on every page where you want that sidebar.
This is an example of base.html
<!DOCTYPE html>
<html>
<head>
<title>My Project</title>
</head>
<body>
<header>
<ul>
<li>Home</li>
<li>News</li>
</ul>
</header>
{% block content %}{% endblock content %}
</body>
</html>
Include base.html in other Html files
{% extends "base.html" %}
{% block content %}
<h2>Content for My App</h2>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry..</p>
{% endblock content %}

Related

External URL into a iframe to embed an external url within Django

I would like to embed a pptx that is uploaded into a folder in OneDrive within a iframe tag in a Django template. I have the urls stored in a model and saved into the SQLite database. In this sense, in the views.py file, I have the following code:
context = {
'selectedunit': selectedunit,
'url_to_be_inserted': MyModel.objects.filter(unit=selectedunit)
}
return render(request, 'web.html', context)
The code for web.html is very easy:
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container col-lg-8">
<div class="center">
<iframe class="center" src={{ url_to_be_inserted.url }} width="100%" height="300%" frameborder="0"/>
</div>
</div>
{% endblock %}
The result is the snapshot below:
While, I would like to embed the ppt into the web site. If I directly insert the URL, instead of using the context variable, it works. That is to say:
<iframe class="center" src="https://..." width="100%" height="300%" frameborder="0"/>
In this case, the result is as follows (ppt embedded into the Web site):
The reason why doing in this sense is because, depending on the selectedunit variable, I would like to address a different pptx with a different URL and I would like to dynamically change the pointer (as you see above by filtering the model).
How could I solve it?
Many thanks in advance

Filtering in Django html template

I'm passing two models into the html template
listings - has all the properties of the listed items (like on an auction site)
bids - has a listing field as a foreign key to link to listings (and the user who made a bit, plus the amount)
I'm looping through the listings items to display all their attributes of the individual listings on cards (that works nicely)
I want to display the bid that belongs to the individual listing if there is any (only the highest bid is passed on for each listing in the 'bid' queryset)
I suspect the problem is with the syntax here, but can't find a solution.
<p>{{bids.filter(listingID=listing.listingID)}}</p>
The error message:
Could not parse the remainder: '(listingID=listing.listingID)' from 'bids.filter(listingID=listing.listingID)'
This is my HTML template
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Active Listings</h2>
<div></div>
{%for listing in listings%}
<div class="listingItem">
<div class="listingLeft">
</div>
<div class="listingRight">
<a href={{listing.id}}><h4>{{listing.listingName}}</h4></a>
<p>{{listing.listingDesc}}</p>
<p>Current bid: ${{listing.listingFirstBid}}</p>
<p>{{bids.filter(listingID=listing.listingID)}}</p>
<p class="created">Created: {{listing.listingCreated}}</p>
</div>
</div>
{%endfor%}
{% endblock %}

Showing list of items including item details on same page in Django

In a Django v3.x app I would like to display a list of uploaded file names (e.g. images) in the left hand side of the screen. When a user clicks on one of those, I'd like to display the actual file/image on the right hand side of the screen. I am still new to Django and have used both ListView and DetailView separately, but not in such a combination. I'm not sure how this can be achieved.
Using a little Bootstrap magic, I can create a split screen easily. Hence, my template would look somehow like this:
<div class="row">
<div class="col-md-5 left">
{% for image in images %}
<div class="card">
<h4>{{ image.url }}</h4>
View
</div>
{% endfor %}
</div>
<div class="col-md-5 right">
{# TODO: When the user clicks on the View url above, then I'd
like to load the actual image here on the right hand side of the
screen inside this div-tag. #}
</div>
</div>
Question 1: How can I achieve loading a selected image from a list? Can I still use ListView and DetailView, or do I need to write my own View logic?
Question 2: Ideally, I'd like to NOT re-send the whole page from the server to the client, because the list of images in the lefthand-side could potentially be long and require pagination. So, when the user clicks View, then, ideally, I'd like to load only the document from the server. Is this somehow feasible?
Well I have made a sample code and you can refer to it and get some idea.
<!--Carousel Wrapper-->
<div id="carousel-thumb" class="carousel slide carousel-fade carousel-thumbnails"
data-ride="carousel">
<!--Slides-->
<div class="row">
<div class="col-lg-8">
<div class="carousel-inner" role="listbox">
{% for latest in latest_course %}
<div class="carousel-item {% if forloop.counter0 == 0 %}active{% endif %}">
<img class="d-block w-100" src="{{latest.poster.url}}" alt="First slide">
</div>
{% endfor %}
</div>
</div>
<!--/.Slides-->
<div class="col-lg-4">
<ol class="slider_list">
{% for latest in latest_course %}
<li data-target="#carousel-thumb" data-slide-to="{{forloop.counter0}}"
class="active"> <img class="img-thumbnail" width="100px" height=100px src="
{{latest.poster.url}}"
class="img-fluid"></li>
{% endfor %}
</ol>
</div>
and the output looks like this
Here, you can see the list on the right side and when you select an item the selected item loads in the left side. This way you can style your template the way you want.
basically you want to show the selected item from the list on the other side like a slideshow

Django and tabbed navigationin templates

I am building a django project which among others has a customer model. Any customer can be a foreign key to some calendar entry models or some picture models. I want to be able to get in to a customers page (e.g domain/customoer/1) and be able to navigate to the different models the customer is related with (e.g all the pictures for the customer, all the calendar entries of the customer). I am using bootstrap for the "presentation of the site. My idea was to use tabs. So I created a pil for my main template the customer.html
<ul class="nav nav-pills">
<li class="active">Personal Data</li>
<li>History</li>
<li>Analysis</li>
<li>Diagnosis</li>
<li>Treatment</li>
<li>Appointments</li>
<li>Graphics</li>
</ul>
and i was thinking of including a template for each pill
<div class="tab-content">
<div id="personal-data" class="tab-pane active ">
<div id="history" class="tab-pane">History is in the making</div>
<div id="analysis" class="tab-pane">
{% include 'customer/analysis.html' with customer=customer %}
</div>
<div id="diagnosis" class="tab-pane">Diagnosis is differential</div>
<div id="treatment" class="tab-pane">Treatment what treatment??</div>
<div id="appointments" class="tab-pane">Ap point ment</div>
<div id="graphics" class="tab-pane">Now this is going to be hard!</div>
The templates in each tab can do different things like upload pics navigate to different pages etc.
When i hit on a pill the url (domain/customer/1/) won't change (naturally) to inform me to which tab i am at the moment. So my question is how can i know in which tab i am ath the moment? I want the user to be able to do different things from different tabs (upload pics etc) and I want to be able to redirect to the specific tab after the view is called? Maybe #id could be appended to the url to specify the tab, but it doesn't happen with bootstrap.
What is the best way to deal with tabs in django? Ajax maybe? Will I not have the same problem? Any ideas or lings would be nice too
I use template inheritance for this kind of thing. It's simple and flexible. For example, you can define your main navigation in your base template like so:
...
<li {% block news %}{% endblock %}>News</li>
<li {% block features %}{% endblock %}>Features</li>
<li {% block sport %}{% endblock %}>Sport</li>
...
Then, in your base templates for each of those apps you'd have something like:
<!-- news/base_news.html -->
{% extends 'base.html' %}
...
{% block news %}class="active"{% endblock %}
...

How to render menu with one active item with DRY?

I would like to render a constructions like:
<a href='/home'>Home</a>
<span class='active'>Community</span>
<a href='/about'>About</a>
Where Community is selected menu item. I have menu with same options for several templates but I would not like to create combinations for each template:
<!-- for Home template-->
<span class='active'>Home</span>
<a href='/comminuty'>Community</a>
<a href='/about'>About</a>
...
<!-- for Community template-->
<a href='/home'>Home</a>
<span class='active'>Community</span>
<a href='/about'>About</a>
...
<!-- for About template-->
<a href='/home'>Home</a>
<a href='/community'>Community</a>
<span class='active'>About</span>
We have permanent list of menu items, so, it can be more effective way - to create only one generalized structure of menu then render menu with required option for template.
For example it could be a tag that allows to do that.
Figured out another way to do it, elegant enough thanks to this answer : https://stackoverflow.com/a/17614086/34871
Given an url pattern such as:
url(r'^some-url', "myapp.myview", name='my_view_name'),
my_view_name is available to the template through request ( remember you need to use a RequestContext - which is implicit when using render_to_response )
Then menu items may look like :
<li class="{% if request.resolver_match.url_name == "my_view_name" %}active{% endif %}">Shortcut1</li>
<li class="{% if request.resolver_match.url_name == "my_view_name2" %}active{% endif %}">Shortcut2</li>
etc.
This way, the url can change and it still works if url parameters vary, and you don't need to keep a list of menu items elsewhere.
Using template tag
You can simply use the following template tag:
# path/to/templatetags/mytags.py
import re
from django import template
try:
from django.urls import reverse, NoReverseMatch
except ImportError:
from django.core.urlresolvers import reverse, NoReverseMatch
register = template.Library()
#register.simple_tag(takes_context=True)
def active(context, pattern_or_urlname):
try:
pattern = '^' + reverse(pattern_or_urlname)
except NoReverseMatch:
pattern = pattern_or_urlname
path = context['request'].path
if re.search(pattern, path):
return 'active'
return ''
So, in you your template:
{% load mytags %}
<nav><ul>
<li class="nav-home {% active 'url-name' %}">Home</li>
<li class="nav-blog {% active '^/regex/' %}">Blog</li>
</ul></nav>
Using only HTML & CSS
There is another approach, using only HTML & CSS, that you can use in any framework or static sites.
Considering you have a navigation menu like this one:
<nav><ul>
<li class="nav-home">Home</li>
<li class="nav-blog">Blog</li>
<li class="nav-contact">Contact</li>
</ul></nav>
Create some base templates, one for each session of your site, as for example:
home.html
base_blog.html
base_contact.html
All these templates extending base.html with a block "section", as for example:
...
<body id="{% block section %}section-generic{% endblock %}">
...
Then, taking the base_blog.html as example, you must have the following:
{% extends "base.html" %}
{% block section %}section-blog{% endblock %}
Now it is easy to define the actived menu item using CSS only:
#section-home .nav-home,
#section-blog .nav-blog,
#section-contact .nav-contact { background-color: #ccc; }
I found easy and elegant DRY solution.
It's the snippet:
http://djangosnippets.org/snippets/2421/
**Placed in templates/includes/tabs.html**
<ul class="tab-menu">
<li class="{% if active_tab == 'tab1' %} active{% endif %}">Tab 1</li>
<li class="{% if active_tab == 'tab2' %} active{% endif %}">Tab 2</li>
<li class="{% if active_tab == 'tab3' %} active{% endif %}">Tab 3</li>
</ul>
**Placed in your page template**
{% include "includes/tabs.html" with active_tab='tab1' %}
You could make a context variable links with the name, URL and whether it's an active item:
{% for name, url, active in links %}
{% if active %}
<span class='active'>{{ name }}</span>
{% else %}
<a href='{{ url }}'>{{ name }}</a>
{% endif %}
{% endfor %}
If this menu is present on all pages, you could use a context processor:
def menu_links(request):
links = []
# write code here to construct links
return { 'links': links }
Then, in your settings file, add that function to TEMPLATE_CONTEXT_PROCESSORS as follows: path.to.where.that.function.is.located.menu_links. This means the function menu_links will be called for every template and that means the variable links is available in each template.
I have come up with a way to utilize block tags within menu-containing parent template to achieve something like this.
base.html - the parent template:
Home
About
Contact
{% block content %}{% endblock %}
about.html - template for a specific page:
{% extends "base.html" %}
{% block menu_about_class %}active{% endblock %}
{% block content %}
About page content...
{% endblock %}
As you can see, the thing that varies between different page templates is the name of the block containing active. contact.html would make use of menu_contact_class, and so on.
One benefit of this approach is that you can have multiple subpages with the same active menu item. For example, an about page might have subpages giving information about each team members of a company. It could make sense to have the About menu item stay active for each of these subpages.
Here ist my solution:
{% url 'module:list' as list_url %}
{% url 'module:create' as create_url %}
<ul>
<li>List Page</li>
<li>Creation Page</li>
</ul>
Assuming the nav item is a link with the same URL as the current page, you could just use JavaScript. Here's an annotated method that I use to add a class="active" to a li in a navigation menu with class="nav":
// Get the path name (the part directly after the URL) and append a trailing slash
// For example, 'http://www.example.com/subpage1/sub-subpage/'
// would become '/subpage1/'
var pathName = '/' + window.location.pathname.split('/')[1];
if ( pathName != '/' ) { pathName = pathName + '/'; }
// Form the rest of the URL, so that we now have 'http://www.example.com/subpage1/'
// This returns a top-level nav item
var url = window.location.protocol + '//' +
window.location.host +
pathName;
console.log(url);
// Add an 'active' class to the navigation list item that contains this url
var $links = document.querySelectorAll('.nav a');
$link = Array.prototype.filter.call( $links, function(el) {
return el.href === url;
})[0];
$link.parentNode.className += ' active';
This method means you can simply pop it into your base template once and forget about it. No repetition, and no manual specification of the page URL in each template.
One caveat: this obviously only works if the url found matches a navigation link href. It would additionally be possible to specify a couple of special use cases in the JS, or target a different parent element as needed.
Here's a runnable example (keep in mind, snippets run on StackSnippets):
// Get the path name (the part directly after the URL) and append a trailing slash
// For example, 'http://www.example.com/subpage1/sub-subpage/'
// would become '/subpage1/'
var pathName = '/' + window.location.pathname.split('/')[1];
if ( pathName != '/' ) { pathName = pathName + '/'; }
// Form the rest of the URL, so that we now have 'http://www.example.com/subpage1/'
// This returns a top-level nav item
var url = window.location.protocol + '//' +
window.location.host +
pathName;
console.log(url);
// Add an 'active' class to the navigation list item that contains this url
var $links = document.querySelectorAll('.nav a');
$link = Array.prototype.filter.call( $links, function(el) {
return el.href === url;
})[0];
$link.parentNode.className += ' active';
li {
display: inline-block;
margin: 0 10px;
}
a {
color: black;
text-decoration: none;
}
.active a {
color: red;
}
<ul class="nav">
<li>
Example Link
</li>
<li>
This Snippet
</li>
<li>
Google
</li>
<li>
StackOverflow
</li>
</ul>
I ran into this challenge today with how to dynamically activate a "category" in a sidebar. The categories have slugs which are from the DB.
I solved it by checking to see category slug was in the current path. The slugs are unique (standard practice) so I think this should work without any conflicts.
{% if category.slug in request.path %}active{% endif %}
Full example code of the loop to get the categories and activate the current one.
{% for category in categories %}
<a class="list-group-item {% if category.slug in request.path %}active{% endif %}" href="{% url 'help:category_index' category.slug %}">
<span class="badge">{{ category.article_set.count }}</span>
{{ category.title }}
</a>
{% endfor %}
Based on #vincent's answer, there is an easier way to do this without messing up with django url patterns.
The current request path can be checked against the rendered menu item path, and if they match then this is the active item.
In the following example I use django-mptt to render the menu but one can replace node.path with each menu item path.
<li class="{% if node.path == request.path %}active{% endif %}">
node.title
</li>
I am using an easier and pure CSS solution. It has its limitations, of which I know and can live with, but it avoids clumsy CSS class selectors, like this:
index
Because a space character before active is missing the class selector gets called itemactive instead of item active and this isn't exactly too difficult to get wrong like that.
For me this pure CSS solution works much better:
a.item /* all menu items are of this class */
{
color: black;
text-decoration: none;
}
a.item[href~="{{ request.path }}"] /* just the one which is selected matches */
{
color: red;
text-decoration: underline;
}
Notice: This even works if the URL has additional path components, because then href also matches partially. That could eventually cause 'collisions' with more than one match, but often enough it just works, because on well structured websites a "subdirectory" of an URL usually is a child of the selected menu item.
I personally find the simplest way is to create blocks for each link like so:
# base.py
...
<a href="{% url 'home:index' %}" class={% block tab1_active %}{% endblock %}>
...
<a href="{% url 'home:form' %}" class={% block tab2_active %}{% endblock %}>
...
And then in each relative template declare that link as "active" e.g.:
tab1 template:
{% block tab1_active %}"active"{% endblock %}
tab2 template:
{% block tab2_active %}"active"{% endblock %}
Simply use template tags
# app/templatetags/cores.py
from django import template
from django.shortcuts import reverse
register = template.Library()
#register.simple_tag
def active(request, url, classname):
if request.path == reverse(url):
return classname
return ""
Do like this in your template
{% load cores %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example</title>
</head>
<body>
<div>
myUrl
</div>
</body>
</html>
Have fun 😎