request.path does not match expected dynamic url - python

I'm trying to highlight specific buttons in the navigation bar when I'm on a specific page and hyperlink to it when i'm not. The url for this page is a dynamic url however and using the {% url ... as var %} syntax is not making the specific buttons highlighted when they should be.
The issue here is that the button does not even show up at all. I narrowed it down to the request.path not matching with the dynamic url path. Normal urls (without the /str:something) seem to match perfectly.
in navbar.html i've tried to define the comparison_url (before all other code) as follows, but nothing seems to work so far:
{% url 'comparison' as comp_url %}
{% url 'comparison' sub_name as comp_url %}
{% url 'comparison' suburb_name as comp_url %}
{% url 'comparison' sub_name=suburb_name as comp_url %}
{% url 'comparison' vergelijking.suburb as comp_url %}
urls are defined as follows in urls.py:
urlpatterns = [
path("vergelijking/<str:sub_name>", views.ComparisonView.as_view(), name="comparison"),
path("signalen/<str:sub_name>", views.RadarView.as_view(), name="signals"),
path("oorzaken/<str:sub_name>", views.CausationsView.as_view(), name="causation"),
]
in navbar.html, where the actual problem lies:
{% url 'comparison' sub_name as comp_url %}
{% url 'signals' sub_name as sig_url %}
{% url 'causation' sub_name as comp_url %}
{% if request.path == comp_url %}
<li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded active">Vergelijking</a></li>
{% elif request.path == sig_url or request.path == caus_url %}
<li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded" href="{% url 'comparison' sub_name=suburb_name%}">Vergelijking</a></li>
{% endif %}
my base.html includes the navbar.html and the comparison.html extends base.html. There is no view for the navbar.html or base.html. My comparisonview looks like this (municipality details are loaded into the context):
class ComparisonView(LoginRequiredMixin, TemplateView):
"""map of municipality and suburbs with tooltip info"""
template_name = 'comparison.html'
def get_context_data(self, **kwargs):
context = super(ComparisonView, self).get_context_data(**kwargs)
context['suburb_name'] = self.kwargs['sub_name']
municipality_name = Suburb.objects.get(name=self.kwargs['sub_name']).municipality.name
context['municipality_name'] = municipality_name
suburb_list = Suburb.objects.filter(municipality__name=municipality_name)
suburbs_signals_dict = {}
for s in suburb_list:
suburbs_signals_dict[s.name] = s.get_signals()
context['suburb_signals'] = dumps(suburbs_signals_dict)
return context
I think the mistake is in the way i define my comp_url but i'm not exactly sure. Does anyone know what I'm doing wrong?

the view was missing a request as a parameter (whenever i was calling on request.path, it was equating the to be matched link with null as request.path did not exist). I solved this by adding the path to the context:
context['path'] = quote(self.request.path)
The quote was in my case necessary since self.request.path can have spaces in a url whereas comp_url has '%20' for spaces. After I could call on path like so:
{% if path == comp_url %}
And the problem was solved

Related

Django How to get GET parameters in template

I'm working on a django project.
I'm wondering how to get GET parameters in template so that I can make corresponding tab active.
I tried the code below, but it didn't work.
<a class="list-group-item {% if '?q=' in request.path %}active{% endif %}" href="{% url 'blah'%}"> Foo </a>
Thank you in advance.
Get it in view and send it as parameter in render
active = ('?q=' in request.path)
render(..., context={"active": active})
and use it in template
class="list-group-item {% if active %}active{% endif %}"
Or get it as
if '?q=' in request.path:
extra_class = "active"
else:
extra_class = ""
render(..., context={"extra_class": extra_class})
and set in template without if
class="list-group-item {{ extra_class }}"
BTW:
You could get it also as
query = request.GET.get('q', '')
render(..., context={"query": query})
and use it in template to set class and to display query
You search: {{ query }}
class="list-group-item {% if query %}active{% endif %}"

django {% url %} template looping

my url.py
app_name="application_name"
urlpatterns=[
url(r"^staff/",include('application_name.staff_url', namespace='staff')),
url(r"^customer/",include('application_name.customer_url', namespace='customer')),
]
staff_url.py
from application_name import views
app_name="staff"
urlpatterns=[
url(r"^customers/",views.customers, name='customers'),
url(r"^orders/$", views.orders, name='orders'),
url(r"^payments/$", views.payments, name='payments'),
]
customer_url.py
from application_name import views
app_name="customer"
urlpatterns=[
url(r"^items/",views.items, name='items'),
url(r"^checkout/$", views.checkout, name='checkout'),
url(r"^make_payment/$", views.make_payment, name='make_payment'),
]
staf url would be staff/orders or staff/payments customer urls would be customer/items or customer/checkout etc
In my view file I have put every link inside a list which would be iterated inside the template and placed it inside a session
This is my view.py
staffLink=[
{'linkfield':"customers", 'name':"Customers",'slug':"staff"},
{'linkfield':"orders", 'name':"Orders",'slug':"staff"},
{'linkfield':"payments", 'name':"payments",'slug':"staff"}]
links=staffLink
request.session['links']= links
request.session['sub']= 'staff'
context_dict = {'links':links}
This is my html template
{% for link in request.session.links %}
{% if request.session.sub =="staff" %}
<a href="{% url 'application_name:staff' link.linkfield as the_url %}" class="nav-link">
{% elif request.session.sub =="customer" %}
<a href="{% url 'application_name:customer' link.linkfield as the_url %}" class="nav-link">
{% endif %}
{% endfor %}
Pl
This are the following result
When I include the if statement i.e. {% if request.session.sub =="staff" %}. The following error is produced
django.template.exceptions.TemplateSyntaxError: Could not parse the remainder: '=="staff"' from '=="staff"'
When I exclude the if statement so making it just <a href="{% url 'application_name:staff' link.linkfield as the_url %}" class="nav-link">
I did this for testing purposes. I get the following error
django.urls.exceptions.NoReverseMatch: Reverse for 'staff' not found. 'staff' is not a valid view function or pattern name.
Please what am I to do to get the if statement working alongside the anchor statement
You should write a space between the == and the "staff" string, so:
{% if request.session.sub == "staff" %}
…
{% endif %}
as for the URL, you not refer to a URL which is an include(…) since that is a collection of URLs. For example:
<a href="{% url 'staff:customers' link.linkfield as the_url %}" class="nav-link">

Django Get Root Path From Current URL

I am developing a Django website using the Wagtail CMS. I have a navbar at the top of the page where using template tags, it loops through pages in the navigation variable.
{% for item in navigation.menu_items.all %}
<a class="nav-link {% if request.get_full_path == item.link %}active{% endif %}" href="{{ item.link }}" {% if item.open_in_new_tab %} target="_blank"{% endif %}>{{ item.title }}</a>
{% endfor %}
Say that the URL is http://localhost:8000/blog/ and the page URL is the same, then the active class is applied to that iteration.
The problem arises when I am on a page with the URL such as http://localhost:8000/blog/example-blog-post/, this does not match with http://localhost:8000/blog/ and the active class is not applied, even though I am in the blog.
Is there a way to strip the URL and only keeping the root path, so http://localhost:8000/blog/example-blog-post/ becomes http://localhost:8000/blog/ so that the active class can be applied to subpages in the directory?
You can use slice filter
{% if request.path|slice:":5" == item.link %} active{% endif %}
OR
You can use in operator.
So instead {% if request.get_full_path == item.link %} do {% if item.link in request.get_full_path %} or to catch homepage {% if request.get_full_path in item.link and request.get_full_path != '/' or request.get_full_path == item.link %}
This probably isn't the most efficient way, but at the moment for me, it's the only way.
I created a custom template tag which takes in the context and the menu item object, then returns the active class name if the current URL matches the URL of the nav-item (item)
In the HTML, as each nav-item is iterated, the item is passed to the get_active method (a custom template tag that I made)
{% load menu_tags %}
{% get_menu "MAIN" as navigation %}
{% for item in navigation.menu_items.all %}
{% get_active item as active_class %}
<a class="nav-link {{ active_class }}" href="{{ item.link }}" {% if item.open_in_new_tab %} target="_blank"{% endif %}>{{ item.title }}</a>
{% endfor %}
Template tag:
#register.simple_tag(takes_context=True)
def get_active(context, item):
request = context['request']
currentURL = request.path
linkURL = item.link
currentURLStripped = str(currentURL).replace("/", "")
linkURLStripped = str(linkURL).replace("/", "")
if linkURLStripped=="" and currentURLStripped=="":
return "active"
elif linkURLStripped in currentURLStripped and linkURLStripped!="":
return "active"
else:
return ""
The code above simply takes the URL of the page the user is currently on, for example, if the user is on http://localhost:8000/blog then currentURL will be /blog/. The linkURL is the URL property of the item object, for the item object which links to the contact me page, its URL property will be /contact-me/ and thus the linkURL will be the same.
The method simply strips the "/" from the URL strings. If the URL is for the homepage (i.e. it's /) then the variable will be empty. if linkURLStripped=="" and currentURLStripped=="": catches the homepage.
elif linkURLStripped in currentURLStripped and linkURLStripped!="": catches the other pages and ignores the homepage.

How to pass urlname as a variable to url tag in django

I have a url defined in urls.py of an application
urlpatterns = [
url(r'^group/create', create_group, name='create_group'),
url(r'^account/create', create_account, name='create_account'),
]
context contains
{'buttons': {'create_account': {'btn_text': 'Create Account',
'secondary': 'Add a new accounting ledger',
'url': 'create_account'}}
How should I use url in the template.
{% for button in buttons %}
<li class="collection-item">
<div>
{% with btn_url=button.url %}
<a class="btn" href="{% url btn_url %}">{{ button.btn_text }}</a>
{% endwith %}
<span class="black-text">{{ button.secondary }}</span>
</div>
</li>
{% endfor %}
The above code in the template throws
Reverse for '' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
How should I pass the url name as a variable into the url template tag?
Or if should I some how generate the whole url in my view itself, how should the url be generated?
I personally don't think it's possible. I suggest you using reverse in your views.py to interpret the url first, then pass the interpreted result into template:
from django.core.urlresolvers import reverse
url = reverse('create_account')
# add url to your context
According to django docs, reverse would have the same result as you use url template tag in the template.
In your context, buttons is a dictionary, so looping through {% for button in buttons %} will only loop through the keys of the dictionary, i.e. ['btn_text',]
You might want to loop through the items or values instead:
{% for key, value in buttons.items %}
<a class="btn" href="{% url value.btn_url %}">{{ value.btn_text }}</a>
{% endfor %}
or, if you don't need the keys, you can loop through the values
{% for value in button.values %}
<a class="btn" href="{% url value.btn_url %}">{{ value.btn_text }}</a>
{% endfor %}
Note that dictionaries are not ordered. If you are worried about the order of the items in the dictionary, then use a different data structure like a list or ordered dict.

Django NoReverseMatch error with valid url config and views

I'm getting a NoReverseMatch error in my template rendering.
Here's the relevant template:
<ul id='comments'>
{% for comment in comments %}
<li class='comment'>
<img class='gravatar' src='{{ comment.User|gravatar:50}}' alt='{{ comment.User.get_full_name }}' \>
<a href='{% url 'dashboard.views.users.profile' comment.User.id %}' class='user'>
{{comment.User.get_full_name}}
</a>
<p class='comment-timestamp'>{{comment.created}}</p>
<p class='comment-content'>{{comment.comment|striptags}}<br>
{% if user == comment.user or user = report.user %}
Delete</p>
{% endif %}
</li>
{% endfor %}
The error is given on the url 'mokr.delete_comment' line
Here's the view:
def delete_comment(request, comment_id):
comment = get_object_or_404(ReportComment, id = comment_id)
report = comment.MgmtReport
comment.delete()
project = report.project
return HttpResponseRedirect(reverse('show_post', args=(project.url_path, report.id)))
and the section of urls.py
(r'^mokr/comment/(\d+)/delete/$', mokr.delete_comment),
url(r'^mokr/show/([^\.]*)/(\d+)/$', mokr.show, name='show_post'),
You're passing two arguments to the template in your call to reverse in the delete_comment view; args=(project.url_path, report.id) but your urls.py lists;
(r'^mokr/comment/(\d+)/delete/$', mokr.delete_comment),
Which can only accept one parameter.
Alter your urls.py to add a name argument to your delete comment url.
(r'^mokr/comment/(\d+)/delete/$', mokr.delete_comment, name="delete_comment"),
Then try using this in your template;
{% url 'delete_comment' comment.id %}
See naming URL patterns and reverse resolution of URLs

Categories

Resources