Calling a class-based-view from template - django-templates

I'm new to Django/Python and working with Django 2.
In urls.py I defined:
> urlpatterns = [ path('delivery/add'/,views.DeliveryCreate.as_view(),name='delivery-add'), ]
Within the template (app/template/app/main.html) the call is:
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Deliveries
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{% url 'delivery/add' %}">Create Delivery ...</a>
</div>
</li>
The template (app/template/app/delivery_form.html) exists
but this results in an Exception value
Reverse for 'delivery/add' not found. 'delivery/add' is not a valid view function or pattern name.
With path('delivery-add'/...) instead of path('delivery/add'/...) it works for href="{% url 'delivery-add'...%}
Why it doesn't work with '/add' ?
Thx

The {% url %} template tag and reverse function both work with the name of your url pattern, not the actual url!
So since you've defined your pattern as
urlpatterns = [ path('delivery/add'/, views.DeliveryCreate.as_view(),name='delivery-add'), ]
i.e with a name of 'delivery-add' then you have to pass that to {% url %} as you've already experienced, i.e {% url 'delivery-add' %} will work.
Also please notice that there's a trailing / outside of the string in your pattern ( path('delivery/add'/... ) that / definitely needs to be removed!

Related

How to keep the tab active? ASP.NET Core Razor Pages

Hi there,
I have a problem with my tabs in navbar.
The result I wish:
See the "Home" tab class active by default
Clicking on another tab must to remove active class from the <a> that is already active (at the starting point it is "Home" tab)
Add the same class active to the tab I click on (which also mean that app redirects me)
Keep the clicked tab active
What I've got so far:
I see the "Home" tab set active by default
Clicking on any tab removes class active as I mentioned above and adds the same class to the clicked tab
Redirection happens and "Home" tab returns its default state (becomes active again)
I share my code below:
HTML
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse" id="navigation">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link active" id="home" asp-area="" asp-page="/home/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" id="declarations" asp-area="" asp-page="/declarations/Index">Declarations</a>
</li>
<li class="nav-item">
<a class="nav-link" id="topics" asp-area="" asp-page="/topics/Index">List of Topics</a>
</li>
<li class="nav-item">
<a class="nav-link" id="contacts" asp-area="" asp-page="/contacts/Index">Contacts</a>
</li>
<li class="nav-item">
<a class="nav-link" id="faq" asp-area="" asp-page="/faq/Index">FAQ</a>
</li>
</ul>
</div>
jQuery
$("#navigation .navbar-nav a").click(function() {
$("#navigation .navbar-nav").find("a.active").removeClass("active");
$(this).addClass("active");
localStorage.className = "active";
});
$(document).ready(function() {
stayActive();
});
function stayActive() {
$(this).children().addClass(localStorage.className);
}
Since you are using Razor page, everytime user clicks on a tab, the page will be rendered again on server and then sent back. Therefore I suggest that we set the active class on serverside based on the current route.
Add a new HtmlHelper class
public static class HtmlHelperExtensions
{
public static string ActiveClass(this IHtmlHelper htmlHelper, string route)
{
var routeData = htmlHelper.ViewContext.RouteData;
var pageRoute = routeData.Values["page"].ToString();
return route == pageRoute ? "active" : "";
}
}
Go to your _ViewImports.cshtml and add this import.
Without this, it will not recognize the helper we're about to add in step 3.
#using <Namespace of the class you wrote in step 1, if not already here>
Then your cshtml will be
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse" id="navigation">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link #Html.ActiveClass("/home/Index")" id="home" asp-area="" asp-page="/home/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link #Html.ActiveClass("/declarations/Index")" id="declarations" asp-area="" asp-page="/declarations/Index">Declarations</a>
</li>
...Same for 3 other tabs, make sure that the route you pass in ActiveClass method
...must be the same as the route in asp-page
...If you're afraid of duplication, make some static class to store these routes as constants
</ul>
</div>
In addition to #Nam Le answer I suggest complete solution.
I've found the way how can we use the exception properly.
First of all, as we set active class on serverside based on the current route, we have to add asp-route-routeId="{routeId:int}" in the cshtml we work with.
Secondly, use this jQuery code:
jQuery
$("#navigation .navbar-nav a").click(function() {
$("#navigation .navbar-nav").find("a.active").removeClass("active");
$(this).addClass("active");
localStorage.className = "active";
});
$(document).ready(function() {
stayActive();
});
function stayActive() {
$(this).addClass(localStorage.className);
}
And the last step is to setup "launchUrl": "route/routeId" in the launchSetting.json file to run the application with certain route. This action make our HtmlHelper extension react and add active status to the tab we want.
Hope that here is no any gross mistakes in the solution I suggest :)
UPD: don't forget to add route in cshtml #page "/route/routeId"

How to use indexes in XPath

I do have popup where are three dropdowns, ids are unique
with each popup generation:
The first element:
<a aria-required="true" class="select" aria-disabled="false" aria-
describedby="5715:0-label" aria-haspopup="true" tabindex="0" role="button"
title="" href="javascript:void(0);" data-aura-rendered-by="5733:0" data-
interactive-lib-uid="10">Stage 1 - Needs Assessment</a>
While I'm able to identify the element above by simple xpath="//*[#class='select'][1]", the other two, which look same to me (example below), can't be identified by index like //*[#class='select'][2], tried 'following' without success, but I may be not correct with syntax.
Example of dropdown element I'm unable to locate..
<a aria-required="false" class="select" aria-disabled="false" aria-
describedby="6280:0-label" aria-haspopup="true" tabindex="0" role="button"
title="" href="javascript:void(0);" data-aura-rendered-by="6290:0" data-
interactive-lib-uid="16">--None--</a>
Any ideas what am I missing?, except advanced xpath knowledge..
Thank you!
//*[#class='select'][2] will return you required node only if both links are children of the same parent, e.g.
<div>
<a class="select">Stage 1 - Needs Assessment</a>
<a class="select">--None--</a>
</div>
If links are children of different parents, e.g.
<div>
<a class="select">Stage 1 - Needs Assessment</a>
</div>
<div>
<a class="select">--None--</a>
</div>
you should use
(//*[#class='select'])[1]
for first
(//*[#class='select'])[2]
for second

Web scraping Linkedin Job posts using Python, Selenium & Phantomjs

Some LinkedIn job posts contain a see more button that expands the whole job description:
https://www.linkedin.com/jobs/view/401243784/?refId=3024203031501300167509&trk=d_flagship3_search_srp_jobs
I tried to expand it using the element.click() but the source I get after expansion contains some placeholder divs instead of the original div. How, can I scrap those hidden texts.
This is what I get from driver.page_source
<div class="jobs-ghost-placeholder jobs-ghost-placeholder--medium jobs-ghost-placeholder--thin mb2"></div>
<div class="jobs-ghost-placeholder jobs-ghost-placeholder--x-small jobs-ghost-placeholder--thin mb2"></div>
<div class="jobs-ghost-placeholder jobs-ghost-placeholder--small jobs-ghost-placeholder--thin"></div>
Instead of the source I get from chrome inspect:
<div id="ember7189" class="jobs-description-details pt5 ember-view"> <h3 class="jobs-box__sub-title js-formatted-exp-title">Seniority Level</h3>
<p class="jobs-box__body js-formatted-exp-body">Associate</p>
<!---->
<h3 class="jobs-box__sub-title js-formatted-industries-title">Industry</h3>
<ul class="jobs-box__list jobs-description-details__list js-formatted-industries-list">
<li class="jobs-box__list-item jobs-description-details__list-item">Real Estate</li>
<li class="jobs-box__list-item jobs-description-details__list-item">Information Technology and Services</li>
</ul>
<h3 class="jobs-box__sub-title js-formatted-employment-status-title">Employment Type</h3>
<p class="jobs-box__body js-formatted-employment-status-body">Full-time</p>
<h3 class="jobs-box__sub-title js-formatted-job-functions-title">Job Functions</h3>
<ul class="jobs-box__list jobs-description-details__list js-formatted-job-functions-list">
<li class="jobs-box__list-item jobs-description-details__list-item">Information Technology</li>
<li class="jobs-box__list-item jobs-description-details__list-item">Project Management</li>
<li class="jobs-box__list-item jobs-description-details__list-item">Product Management</li>
</ul>
</div>
I also tried different values for the wait WebDriverWait(driver, 3) but in vain.
code:
employment_type = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, 'div.jobs-description__details>div.jobs-description-details>p.js-formatted-employment-status-body'))).text
raises timeout exception as it only finds those jobs-ghost-placeholder instead of the described css_selector

Phalcon assign view variable inconsistent

Having a problem getting consistent behavior assigning variables to the view. For example:
In controller:
$this->view->media = Media::findFirst(['groupId=0', 'order' => 'RAND()', 'limit' => 1]);
In view:
{% if media is defined %}
<div class="thumbnail">
<img src="{{ static_url('img/media/thumbs/' ~ media.name) }}" class="img-round">
<div class="caption">
<h3>{{ media.title }}</h3>
<p>{{ media.description }}</p>
</div>
</div>
{% endif %}
Which is parsed like:
<?php if (isset($media)) { ?>
<div class="thumbnail">
<img src="<?php echo $this->url->getStatic('img/media/thumbs/' . $this->media->name); ?>" class="img-round">
<div class="caption">
<h3><?php echo $this->media->title; ?></h3>
<p><?php echo $this->media->description; ?></p>
</div>
</div>
<?php } ?>
The problem is that when the parsed version of the template, $media is not accessible via $this so the isset($media) passes, but the references to $this->media returns nothing.
Any way to force $media to be local in scope?
I think I got it.
Misbehaviour description
You have probably declared a media module in your DI(). I was trying quite a lot to reproduce that error, and got it finally when i set a dumb media service among configuration files:
$di->set('media', function() {
return new \stdClass();
});
and than got the same behavior you have - Volt during compilation is not sure, what variable to use and choses $this->media (DI::get('media')) instead of $media or $this->view->media var for obtaining data.
Solution
If you dont want to resign from calling you findFirst result under that variable name, you may bypass that by using View in volt directly:
{% if view.media is defined %}
<div class="thumbnail">
<img src="{{ static_url('img/media/thumbs/' ~ view.media.name) }}" class="img-round">
<div class="caption">
<h3>{{ view.media.title }}</h3>
<p>{{ view.media.description }}</p>
</div>
</div>
{% endif %}
it will generate $this->view->media calls instead of $this->media ones.
+1 on that question.

How do i dynamically/evaluate via expression json property in django template

reading in a JSON for sport. using a partial for matchup markup.
awayteam and home team for most part share identical markup but the JSON properties which I have no control are such below:
<div class="away {{game.awayTeam_last_name|slugify}}">
<a href="#" title="{{game.awayTeam_first_name}} {{game.awayTeam_last_name}}">
<span class="{{league}}-logo"></span>
<span class="city">{{game.awayTeam_first_name}}</span>
{% if game.event_status != "pre-event" %}
<span title="score">{{game.awayTeam_score}}</span>
{% else %}
<span title="record entering game">(0-0)</span>
{% endif %}
</a>
</div>
<span>#</span>
<div class="home {{game.homeTeam_last_name|slugify}}">
<a href="#" title="{{game.homeTeam_first_name}} {{game.homeTeam_last_name}}">
<span class="{{league}}-logo"></span>
<span class="city">{{game.homeTeam_first_name}}</span>
{% if game.event_status != "pre-event" %}
<span title="score">{{game.homeTeam_score}}</span>
{% else %}
<span title="record entering game">(0-0)</span>
{% endif %}
</a>
</div>
is there a way to shrink/refactor the above like some expression valuator to make home and away passed via a variable.
didn't answer own question but i did get Data guys to better format the data, so became..
awayteam: { first_name:'', last_name:'', score:'' }
hometeam: { first_name:'', last_name:'', score:'' }
allowing me to shrink in half the template =)