I have the following dictionary defined in a python config file:
AUTHORS = {
u'MyName Here': {
u'blurb': """ blurb about author""",
u'friendly_name': "Friendly Name",
u'url': 'http://example.com'
}
}
I have the following Jinja2 template:
{% macro article_author(article) %}
{{ article.author }}
{{ AUTHORS }}
{% if article.author %}
<a itemprop="url" href="{{ AUTHORS[article.author]['url'] }}" rel="author"><span itemprop="name">{{ AUTHORS[article.author]['friendly_name'] }}</span></a> -
{{ AUTHORS[article.author]['blurb'] }}
{% endif %}
{% endmacro %}
And I call this via:
<div itemprop="author creator" itemscope itemtype="http://schema.org/Person">
{% from '_includes/article_author.html' import article_author with context %}
{{ article_author(article) }}
</div>
When I generate my Pelican template I get the following error:
CRITICAL: UndefinedError: dict object has no element <Author u'MyName Here'>
If I remove the {% if article.author %} block from my template, the page generates properly with the {{ AUTHORS }} variable displaying correctly. It clearly has a MyName Here key:
<div itemprop="author creator" itemscope itemtype="http://schema.org/Person">
MyName Here
{u'MyName Here': {u'url': u'http://example.com', u'friendly_name': u'Friendly Name', u'blurb': u' blurb about author'}}
</div>
How do I access the MyName Here element correctly in my template?
The article.author isn't just 'Your Name', it's an Author instance with various properties. In your case, you want:
{% if article.author %}
<a itemprop="url" href="{{ AUTHORS[article.author.name].url }}" rel="author">
<span itemprop="name">{{ AUTHORS[article.author.name].friendly_name }}</span>
</a> -
{{ AUTHORS[article.author.name].blurb }}
{% endif %}
or, to reduce some of the boilerplate, you can use:
{% if article.author %}
{% with author = AUTHORS[article.author.name] %}
<a itemprop="url" href="{{ author.url }}" rel="author">
<span itemprop="name">{{ author.friendly_name }}</span>
</a> -
{{ author.blurb }}
{% endwith %}
{% endif %}
as long as you have 'jinja2.ext.with_'in your JINJA_ENVIRONMENT's extensions list.
Note you can use dot.notation rather than index['notation'] in Jinja templates.
Related
I am attempting to learn Django but keep receiving the error " 'endfor', expected 'endblock'. Did you forget to register or load this tag? " when I add the {% for key,value in
price.DISPLAY.items %} {{ key }} {% endfor %} part of the code. How can I fix this? Any help would be great thanks.
home.html
{% extends 'base.html' %} {% block content %} {% for key,value in
price.DISPLAY.items %} {{ key }} {% endfor %}
<br />
<br />
{{ price.DISPLAY }}
<div class="jumbotron">
<h1 class="display-4">Welcome</h1>
</div>
<div class="container">
<div class="row">
{% for info in api.Data %}
<div class="card" style="width: 18rem">
<img src="{{info.imageurl}}" class="card-img-top" alt="{{info.source}}" />
<div class="card-body">
<h5 class="card-title">{{info.title}}</h5>
<p class="card-text">{{info.body}}</p>
<a href="{{info.url}}" class="btn btn-secondary" target="_blank"
>Read more</a
>
</div>
</div>
{% endfor %}
</div>
</div>
{{ api.Data }} {% endblock content %}
A template tag should not span multiple lines. You should write the {% for … %} tag on a single line:
{% extends 'base.html' %} {% block content %}
{% for key,value in price.DISPLAY.items %} {{ key }} {% endfor %}
…
{% endblock content %}
I'm still learning Django and there is still a lot of unknown to me.
The problem is that I can't pull the .pdf (or any other format) to be sent by ajax post method to external API. So on the reciving side I only get the string location of the file not the actual file.
I have put the following javascript code in the generic_list_items_subtemplate.html
{% load i18n %}
{% load static %}
{% load common_tags %}
{% load navigation_tags %}
<div class="row">
<div class="col-xs-12">
<h4>
{% if page_obj %}
{% if page_obj.paginator.num_pages != 1 %}
{% blocktrans with page_obj.start_index as start and page_obj.end_index as end and page_obj.paginator.object_list|length as total and page_obj.number as page_number and page_obj.paginator.num_pages as total_pages %}Total ({{ start }} - {{ end }} out of {{ total }}) (Page {{ page_number }} of {{ total_pages }}){% endblocktrans %}
{% else %}
{% blocktrans with page_obj.paginator.object_list|length as total %}Total: {{ total }}{% endblocktrans %}
{% endif %}
{% else %}
{% blocktrans with object_list|length as total %}Total: {{ total }}{% endblocktrans %}
{% endif %}
</h4>
<hr>
<div class="well center-block">
<div class="clearfix">
<div class="pull-right">
<form action="{% url 'common:multi_object_action_view' %}" class="form-multi-object-action" method="get">
{% if object_list %}
{% if not hide_multi_item_actions %}
{% get_multi_item_links_form object_list %}
{% endif %}
{% if multi_item_actions %}
<fieldset style="margin-top: -10px;">
<input class="check-all" type="checkbox"/>
{{ multi_item_form }}
</fieldset>
{% endif %}
{% endif %}
</form>
</div>
</div>
{% if object_list %}
<hr style="border-bottom: 1px solid lightgrey;">
{% endif %}
<div class="row row-items">
{% for object in object_list %}
<div class="{{ column_class|default:'col-xs-12 col-sm-4 col-md-3 col-lg-2' }}">
<div class="panel panel-primary panel-item">
<div class="panel-heading">
<div class="form-group" id="myform">
<div class="checkbox">
<label for="id_indexes_0">
{% if multi_item_actions %}
{% if multi_select_item_properties %}
<input class="form-multi-object-action-checkbox check-all-slave checkbox" type="checkbox" name="properties_{{ object|get_encoded_parameter:multi_select_item_properties }}" />
{% else %}
<input class="form-multi-object-action-checkbox check-all-slave checkbox" type="checkbox" name="{{ object.get_absolute_url }}" />
{% endif %}
{% endif %}
<span style="color: white; word-break: break-all; overflow-wrap: break-word;">
{% if not hide_object %}
{% if main_object %}
{% with object|object_property:main_object as object %}
{% if not hide_link %}<a name="test" href="{{ object.get_absolute_url }}">{{ object }}</a>{% else %}{{ object }}{% endif %}
{% endwith %}
{% else %}
{% if not hide_link %}{{ object }}{% else %}{{ object }}{% endif %}
{% endif %}
{% endif %}
</span>
</label>
</div>
</div>
</div>
<div class="panel-body">
{% if not hide_columns %}
{% for column in object|get_source_columns %}
<div class="text-center" style="">{% source_column_resolve column=column %}{{ column_result }}</div>
{% endfor %}
{% endif %}
{% for column in extra_columns %}
<div class="text-center"><span class="list-extra-column-label">{{ column.name }}</span>: {{ object|object_property:column.attribute }}</div>
{% endfor %}
{% if not hide_links %}
<p class="text-center">
{% get_menu_links 'object menu' source=object as resolved_links %}
{% for object_navigation_links in resolved_links %}
{% with 'true' as as_dropdown %}
{% include 'navigation/generic_navigation.html' %}
{% endwith %}
{% endfor %}
</p>
{% endif %}
</div>
</div>
</div>
{% empty %}
<div class="col-xs-12">
{% include 'appearance/no_results.html' %}
</div>
{% endfor %}
</div>
<!--</form>-->
{% include 'pagination/pagination.html' %}
</div>
</div>
</div>
<!--{% if object_list %}-->
<form method="post">
{% csrf_token %}
<input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajD1cn">
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-3">
<button id="sendBTN" class="btn btn-success" type="submit">Send checked documents to another database</button>
</div>
<div class="col-md-3"></div>
</div>
</form>
<br>
<br>
<br>
<!--{% endif %}-->
<script type="text/javascript">
'use strict';
var $data = [];
$(document).on("click", "input[type='checkbox']", (e) => {
var name = $(e.target).attr("name");
if($(e.target).prop("checked")){
$data.push(name);
}else{
$data = jQuery.grep($data, function(value) {
return value != name;
});
}
console.log($data);
});
function csrfSafeMethod(method)
{
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if(!csrfSafeMethod(settings.type) && !this.crossDomain)
{
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
document.getElementById("sendBTN").onclick = function() {
var form_data = new FormData();
// form_data.append('file', $('#myform').get(0));
form_data.append('file', $data);
console.log(form_data);
$.ajax({
type: "POST",
// contentType: "application/x-www-form-urlencoded",
contentType : false,
processData: false,
url: "http://192.168.10.22:5000/api/FileRecive/GetDocument",
dataType: "json",
data: form_data,
success: function (data) {
data = $.parseJSON(data);
alert("success");
},
error: function (xhr) {
alert("error - " + xhr.statusText);
}
});
};
$(function() {
$('.row-items > [class*="col"] .panel-item .panel-heading').matchHeight();
$('.row-items > [class*="col"] .panel-item .panel-body').matchHeight();
$('.row-items > [class*="col"] .panel-item').matchHeight();
});
</script>
On the reciving side I am getting
name = "file"
value = "/documents/12/preview/"
But I want to get the file not this string. I have no idea how to target file to send it dirrectly.
The URL "/documents/12/preview/" is the URL to view the document using the user interface. If what you want is the actual file of the document, you need to use Mayan's API. Since documents in Mayan are a collection of versions, you need the ID of the latest version of the document you want. For this the API URL for the document detail which is:
"/api/documents/271/"
This will give you something like this:
From there look up the dictionary key "latest_version" and then the key "download_url". The download URL in the screenshot is "http://127.0.0.1:8000/api/documents/271/versions/267/download/". Do a GET request to this URL and you get the actual file of the document. Save the file in temporary variable (or Javascript Blob file object https://developer.mozilla.org/en-US/docs/Web/API/Blob) and then send it to your custom API with a POST request.
Another option is to just send the "download_url" to your API and have a worker process fetch the document data, that way you don't have to store the binary data of the document in the browsers memory.
For more information about Mayan's API go to "Tools" -> "API Documentation" and you'll get an API documentation view that allows testing the API with the live data in your installation.
I am new to Django, and I am reading one app on github:
https://github.com/rogargon/myrecommendations/blob/web2-html/myrestaurants/urls.py#L18
There is one urlpattern like
url(r'^restaurants/(?P<pk>\d+)/$',
RestaurantDetail.as_view(),
name='restaurant_detail')
It revoke RestaurantDetail view, here: https://github.com/rogargon/myrecommendations/blob/master/myrestaurants/views.py#L36
class RestaurantDetail(DetailView):
model = Restaurant
template_name = 'myrestaurants/restaurant_detail.html'
def get_context_data(self, **kwargs):
context = super(RestaurantDetail, self).get_context_data(**kwargs)
context['RATING_CHOICES'] = RestaurantReview.RATING_CHOICES
return context
Here I know pk is set to one number indicating the id of restaurant, but in the html model, https://github.com/rogargon/myrecommendations/blob/master/myrestaurants/templates/myrestaurants/restaurant_detail.html, I didn't see any where using pk, but the page shows only the one restaurant. Could you how does pk work in this process? How the template know which restaurant I want to show? And why there is no return in this view?
{% extends "myrestaurants/base.html" %}
{% block title %}MyRestaurants - {{ restaurant.name }}{% endblock %}
{% block content %}
<span vocab="http://schema.org/" typeof="Restaurant">
<h1>
<span property="name">{{ restaurant.name }}</span>
{% if user == restaurant.user %}
(edit)
{% endif %}
</h1>
<h2>Address:</h2>
<p>
{{ restaurant.street }}, {{ restaurant.number }} <br/>
{{ restaurant.zipcode }} {{ restaurant.city }} <br/>
{{ restaurant.stateOrProvince }} ({{ restaurant.country }})
</p>
<h2>
Dishes
{% if user.is_authenticated %}
(add)
{% endif %}
</h2>
<ul>
{% for dish in restaurant.dishes.all %}
<li><a href="{% url 'myrestaurants:dish_detail' restaurant.id dish.id %}">
{{ dish.name }}</a></li>
{% empty %}<li>Sorry, no dishes for this restaurant yet.</li>
{% endfor %}
</ul>
<h2>Reviews</h2>
{% if restaurant.restaurantreview_set.all|length > 0 %}
<span rel="aggregateRating">
<p typeof="AggregateRating">
Average rating <span property="ratingValue">{{ restaurant.averageRating|stringformat:".1f" }}</span>
{% with restaurant.restaurantreview_set.all|length as reviewCount %}
from <span property="reviewCount">{{ reviewCount }}</span> review{{ reviewCount|pluralize }}
{% endwith %}
</p>
</span>
<ul rel="review">
{% for review in restaurant.restaurantreview_set.all %}
<li typeof="Review">
<p rel="reviewRating" typeof="Rating">
<span property="worstRating" content="{{ RATING_CHOICES.0.0 }}"></span>
<span property="ratingValue">{{ review.rating }}</span> star{{ review.rating|pluralize }}
{% with RATING_CHOICES|last as best %}
<span property="bestRating" content="{{ best.0 }}"></span>
{% endwith %}
</p>
<p property="description">{% if review.comment %}{{ review.comment }}{% endif %}</p>
<p>Created by <span property="author">{{ review.user }}</span> on
<span property="datePublished" content="{{ review.date|date:'Y-m-d' }}">{{ review.date }}</span></p>
</li>
{% endfor %}
</ul>
{% endif %}
</span>
<h3>Add Review</h3>
<form action="{% url 'myrestaurants:review_create' restaurant.id %}" method="post">
{% csrf_token %}
Message: <textarea name="comment" id="comment" rows="4"></textarea>
<p>Rating:</p>
<p>{% for rate in RATING_CHOICES %}
<input type="radio" name="rating" id="rating{{ forloop.counter }}" value="{{ rate.0 }}" />
<label for="choice{{ forloop.counter }}">{{ rate.1 }} star{{ rate.0|pluralize }}</label>
<br/>{% endfor %}
</p>
<input type="submit" value="Review" />
</form>
{% endblock %}
{% block footer %}
Created by {{ restaurant.user }} on {{ restaurant.date }}
{% endblock %}
The behavior you're asking about ("How the template know which restaurant I want to show") is view behavior, not template behavior.
The template renderer gets passed a restaurant value by the view. The view has no (explicit) return because it's a class-based view - a subclass of DetailView, in particular. DetailView itself inherits standard methods that this view does not override to accept a PK parameter and load a particular instance.
You can read the source code for DetailView to get more of a sense of what's going on, if you like, eg https://github.com/django/django/blob/master/django/views/generic/detail.py - but class-based views are a bit of an advanced topic, and not every project will even use them. I'd focus on other areas first.
I am a bit puzzled by the following behavior of the Django templates, which prevents me from successfully styling the output.
Namely, I have the following template:
<article class="article
{% if article.is_featured %} featured{% endif %}
{% if not article.published %} unpublished{% endif %}">
{% if not detail_view %}
<div class="post-preview">
<a href="{% namespace_url 'article-detail' article.slug namespace=namespace default='' %}">
<h2 class="post-title">
{% render_model article "title" "" "" "striptags" %}
</h2>
{% if article.lead_in %}
<h3 class="post-subtitle">
{% if not detail_view %}
{% render_model article "lead_in" "" "" "truncatewords:'20'|striptags" %}
{% else %}
{% render_model article "lead_in" "" "" "striptags" %}
{% endif %}
</h3>
{% endif %}
</a>
<p class="post-meta" style="margin-bottom: 0;"> Posted by
{% include "aldryn_newsblog/includes/author.html" with author=article.author %}
on {{ article.publishing_date|date:"F d, Y" }}
</p>
<p class="post-meta" style="margin: 0">
<h4 style="display:inline-flex">Categories:</h4>
{% for category in article.categories.all %}
{{ category.name }} {% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
<p class="post-meta" style="margin: 0">
<h4 style="display:inline-flex">Tags:</h4>
{% for tag in article.tag %}
{{ tag.name }} {% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
</div>
<hr>
{% endif %}
{% if detail_view %}
<!-- <h3>Testing template! (from article with detail_view=True)</h3> -->
{% render_placeholder article.content language placeholder_language %}
{% endif %}
</article>
The output of this template is roughly like this:
<article class="article">
<div class="post-preview">
<a href="/articles/third-post/">
<h2 class="post-title">
Third Post
</h2>
<h3 class="post-subtitle">
Third post lead-in text.
</h3>
</a>
<p class="post-meta" style="margin-bottom: 0;"> Posted by
<a href="">
</a>
on September 19, 2017
</p>
<p class="post-meta" style="margin: 0">
<h4 style="display:inline-flex">Categories:</h4>
Programming
</p>
<p class="post-meta" style="margin: 0">
<h4 style="display:inline-flex">Tags:</h4>
</p>
</div>
<hr>
</article>
Although the source HTML seems correct, the browser treats it as the following image illustrates.
What am I missing? Is the template incorrect? Or is this a bug I am observing? I tried this in Safari and Firefox. The result is the same.
No, that is just the browser dev tools trying to make sense of your invalid HTML.
An h element cannot go inside a p element.
Check out this answer:
<h1>, <h2>, <h3>... tags, inline within paragraphs (<p>)
They explain it in depth more in there but basically your <h1,2,3,4> tags being embedded in the <p> tags is considered illegal by the browser and is automatically closing the tags. Use a different tag and it should fix your problem.
I have a simple for loop in Django, outputting a series of teaser stories. Each is wrapped in a div with a class of row. I have an varibale called num_of_rows, that adds a class of hidden after 2 loops, which hides these divs from view with css.
Here's my code:
{% block content %}
<h1>{{ section.title }}</h1>
{% for story in story_list %}
<div class="row {% if num_of_rows > 2 %} hidden{% endif %}">
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
</div>
{% endfor %}
{% endblock %}
What I'd like to do is, instead of adding a class of hidden to each individual row, wrap all of the items after 2 items in a separate div and then hide with CSS from that, using Django. This way I can create a much smoother slide-down effect with jQuery.
You can use the forloop variables for this:
{% for story in story_list %}
{% if forloop.counter == 3 %}<div class="hidden">{% endif %}
<div class="row">
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
</div>
{% if forloop.counter > 2 and forloop.last %}</div>{% endif %}
{% endfor %}