I'm trying to implement pagination. I'm mainly following django documentation for pagination,https://docs.djangoproject.com/en/1.8/topics/pagination/...I'm not sure what i did wrong but the pagination effect is not being activated: When I set page to only have three posts, it still shows nine posts. I didn't do anything special, I just followed the documentation.
def category_detail(request, slug):
obj = NewsCategory.objects.get(slug=slug)
newsInCat = obj.news_set.all() #for the list of news
paginator = Paginator(newsInCat, 3) # Show 25 contacts per page
page = request.GET.get('page')
try:
news_set = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
news_set = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
news_set = paginator.page(paginator.num_pages)
bestInCat = obj.news_set.get_bestInCat()
specialInCat = obj.news_set.get_special()
mustSeeInCat = obj.news_set.get_mustSeeInCat()
recommend = obj.news_set.get_recommend()
ad2 = Sponsored.objects.get_ad2()
context = {
"obj":obj,
"news_set":news_set,
"newsInCat":newsInCat,
"bestInCat":bestInCat,
"specialInCat":specialInCat,
"mustSeeInCat":mustSeeInCat,
"recommend":recommend,
"ad2":ad2
}
and the below is my html...beside pagination, I'm having one more issue. When the title of the post becomes too long that it breaks another line, the format of my page gets messed up. It looks like this
<div class="row">
<article>
{% for news in newsInCat %}
<div class='col-sm-4'>
<div class="content">
<figure class="story-image">
</figure>
<div id="forever "style="margin-bottom:30px;">
<a href='{{news.get_absolute_url }}' style="text-decoration:none; color:#282E5C;"><h4 style="font-size: 18px;
font-weight: 400;">{{news.title}}</h4></a>
</div>
</div>
</div>
{% endfor %}
</article>
</div>
<div class="pagination">
<span class="step-links">
<!-- {% if news_set.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ news_set.number }} of {{ news_set.paginator.num_pages }}.
</span> -->
{% if news_set.has_next %}
Load More
{% endif %}
</span>
</div>
There are two separate problems at work here which have been indicated in the above answers:
You are not using Bootstrap correctly: although you can append multiple <div class="col-sm-4"> together, you will see the irregular collapsing behavior in your screenshot if they are different heights. The purpose of <div class="row"> is to ensure that your columns will appear in separate rows. See Must Bootstrap container elements include row elements? for more information.
You can resolve this with code like the following in your for-loop to add a new row every third item:
{% if forloop.counter|divisibleby:3 %}
</div>
<div class="row">
{% endif %}
You are not using the correct context object in your template: The paginator object is passed as news_set in your context object but the template uses another context object: newsInCat, which is not paginated. If you follow #Sayse's suggestion of using the news_set object, you should be in good shape:
{% for news in news_set %}
As a final suggestion, the <article> tag does not seem to be doing anything besides giving semantic value. Why not just use it instead of the div, so that you have <article class="col-sm-4">?
And as a final note, camelCase is generally frowned on in Python. Try using_underscores_with_lowercase, like you've already done with news_set.
Adding all these suggestions, you would only need to amend your template to something like this:
<div class="row">
{% for news in news_set %}
<article class="col-sm-4">
<!-- add your article content here...and clean it up! You have unnecessary spaces, inconsistent use of single and double quotes, and inline styles that (probably) should be defined in an external stylesheet. -->
</article>
{% if forloop.counter|divisibleby:3 %}
</div>
<div class="row">
{% endif %}
{% endfor %}
</div>
I can speak to your HTML/CSS formatting problem. col-sm-4 tells me you're using Bootstrap, which defines layouts in terms of 12 column width. Bootstrap will always attempt to make the with of all rows equal 12.
Right now, you're looping over all the objects and adding n columns each of width col-sm-4. Booststrap is trying to make sure each takes up a third of the row, but you're adding more that 3 divs, which is more than 12 total column width. Once the column is full, (starting with the 4th news item), Bootstrap moves the divs as closely as it can to the top of the row while still obeying the rule that width can only be 12.
In the case you pictured, Bootstrap offsets the 4th and 5th of divs because the offset allows them to be closer to the top of the row.
To fix this, you'd need to have each set of three news items in it's own row, so that your 3 col-sm-4 divs total a width of 12.
Judging based off the template, you must be still including the full list as well as the paginated set
In your template you are iterating over newsInCat instead of news_set
{% for news in newsInCat %}
should be
{% for news in news_set %}
Related
I'm experiencing a weird behavior with Jinja. I made a dynamic flask route and so I made a jinja modular template, it's just a for loop to create an element for each article present in some data (in a dict) I give to Jinja, the template looks like this :
{% for theme in article_data %}
{% for article in theme["article"] %}
{% if article["main"] == 1 %}
<div style="background-image: url('{{article['content']['image1']}}');" class="theme-item-bg frow space-between">
{% endif %}
{% endfor %}
<div class="wrapper-row space-between pinkfilter">
<div class="uB theme-item-text">{{theme["name"]}}</div>
<div class="pageChanger waves-effect waves-light btn uL primaryB" page="/nos-articles/{{theme['name']}}" title="{{theme['name']}}">Voir plus d'articles</div>
</div>
</div>
{% endfor %}
It does work correctly for most of my pages but for one, it have a really weird behavior, Jinja render one of the article correctly and nest the others in a strong element.
The data used to render the page have the same structure and is correctly parsed.
Is there a way to prevent Jinja from nesting stuff in a strongelement?
There must be either some html inside theme["name"] (fix it by escaping it with theme["name"]|escape), or a <strong> tag not closed in one your templates.
Jinja doesn’t insert random html tags, but the browsers do when trying to parse and fix a broken html code
I have currently a problem to include the pagination function into my project. I know there is LIMIT/OFFSETor yield_per(), but I was not able to implement them.
I am using SQLAlchemy not Flask-SQLAlchemy so paginate wont work.
My Database is not that big. I am trying to show rooms which have been added by a user. So all in all a user will have 20~ rooms, big users maybe 100. I want to show on the profile page the 6 last inserted rooms and if there are more, there should be pagination, like page 2 shows the next 6 etc.
I am using SQLAlchemy-Paginator.
I already implemented it and tested it, it works fine. It also limits already the results depending on which page I am. But how do I access the next page while on HTML?
Here is the python code:
#app.route("/user/logged_in")
#login_required
#check_confirmed
def logged_in():
if current_user.email_verified:
users_room = db_session.query(Zimmer).filter_by(users_id=current_user.id).order_by(desc("id"))
paginator = Paginator(users_room, 2)
for page in paginator:
print "page number of current page in iterator", page.number
print "this is a list that contains the records of current page", page.object_list
return render_template('logged_in.html', paginator=paginator)
return redirect(url_for('unconfirmed'))
Here is the view. The solution must be somewhere here. I can access pages by page.previous_page_number or page.next_page_number. But there is no example in the docu how to do it in view.
<div class="user-rooms">
<h2> Ihre Zimmer </h2>
{% for page in paginator %}
{% if page.number == 1 % }
{% for zimmer in page.object_list %}
{% if zimmer.users_id == current_user.id %}
<div class="col-sm-4 col-xs-6 col-xxs-12 img-holder">
<img src="../static/userimg/{{ zimmer.hauptbild }}"/>
<div class="buttons-del-work"> Bearbeiten Löschen </div>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
If I manually change the page numbers here it show me the correct items, so I feel like I am close:
{% if page.number == 1 % }
Okay here is a solution (which does not use any further methods from the SQLAlchemy-Paginator package). I coded everything myself, but I would still like to know how it is done with page.next_page_number etc.
Explained:
First of all I added an argument (pagenumber) to my logged_in function. Everytime url_for("logged_in", pagenumber=1) is called the pagenumber has to be set to the defaultvalue 1.
I created an empty list, where I add all the page.number items, so I know how many pages my resultset will have:
pages_list = []
for page in paginator:
pages_list.append(page.number)
I use the pages_list also in the view to generate the buttons which can be clicked to see the next page, I also give the pagenumber to the html view:
return render_template('logged_in.html', paginator=paginator, pagenumber=pagenumber, pages_list=pages_list)
Here is the HTML view where I show the buttons:
<div class="col-xs-12">
{% for number in pages_list %}
{{ number }}
{% endfor %}
</div>
Now if a user clicks one of the Buttons the logged_in will be called with a new pagenumber argument (the actual pagesite you clicked)
In the logged_in I added also typecasted pagenumber to int before giving it to html view:
pagenumber = int(pagenumber)
Solution Code
Python:
def logged_in(pagenumber):
if current_user.email_verified:
users_room = db_session.query(Zimmer).filter_by(users_id=current_user.id).order_by(desc("id"))
paginator = Paginator(users_room, 2)
pages_list = []
for page in paginator:
pages_list.append(page.number)
pagenumber = int(pagenumber)
return render_template('logged_in.html', paginator=paginator, pagenumber=pagenumber, pages_list=pages_list)
return redirect(url_for('unconfirmed'))
HTML:
<div class="user-rooms">
<h2> Ihre Zimmer </h2>
{% for page in paginator %}
{% if page.number == pagenumber %}
{% for zimmer in page.object_list %}
<div class="col-sm-4 col-xs-6 col-xxs-12 img-holder">
<img src="../static/userimg/{{ zimmer.hauptbild }}"/>
<div class="buttons-del-work"> Bearbeiten Löschen </div>
</div>
{% endfor %}
{% endif %}
{% endfor %}
</div>
<div class="col-xs-12">
{% for number in pages_list %}
{{ number }}
{% endfor %}
</div>
I have an HTML page displaying a database populated by emails. I have them displayed in a collapsible, and for each post the timestamp of it is what toggles it and the innards are the email itself. The HTML page is structured like this:
{% extends "base.html" %}
{% block content %}
{% for email in emails %}
<div><button class="btn" data-toggle="collapse" data-target="#demo">{{ email.timestamp }}</button>
<div id="demo" class="collapse">
{{ email.body }}
</div>
{% endfor %}
{% endblock %}
relevant portion of views.py
#app.route('/cruz')
def cruz():
u = Politician.query.get(1)
emails = u.emails.all()
return render_template('cruz.html',title='Ted Cruz',emails=emails)
which produces a webpage that looks like this: http://imgur.com/noqC40E
The problem is that no matter which of those timestamps I click, only the first collapsible opens and closes. I've tried a number of things to fix it, mostly messing around with the HTML page and the for blocks and where I place the {{ email.body }}, but nothing I do seems to work. Can anyone see where this is going wrong?
You are generating the same id attribute for your div each time:
<div id="demo" class="collapse">
You almost certainly need to generate unique ids. You could generate unique ids by adding the loop index perhaps:
<div id="demo-{{loop.index}}" class="collapse">
I'm looking to design a site that provides different views of data from a database. I'm new to jinja/flask and templating in general, so it's quite likely I am going about this the wrong way and I'm looking for some feedback or "lordy lord no, you don't ever do that" feedback works too. :)
The basic structure of the page is: a header menu with quick links, a navbar menu pointing to different data sources, another navbar below that providing different views for the data. This 2nd navbar of the views would differ per option selected in the initial navbar.
I envisioned the structure of this to be something like the following:
|-base.html (header menu)
|--navbar1.html (extends base.html, first navbar)
|---navbar2.html (and 3 and 4, etc. - extends navbar1)
|----data_view1.html (and 2, 3, etc. - the returned query, extends navbar2)
This would treat each html as basically a frame and in my mind seems like the right way to do it, and use variables to track which navbar option to highlight through else blocks.
It seems messy though, what would be the best method to achieve the above? Would it be just one html file with a series of elif that would show the navbar2/3/4 and view1/2/3 pages based on what the user selects?
Many thanks in advance.
You certainly can do it this way, but it gets complicated really quickly. The better solution is almost certainly to include all of your navigation in one include:
<nav class="top-navigation">
<ul class="nav nav-first-level">
{{ nav_entry("1st_ds", "1st Data Source", page, sub_page) }}
{{ nav_entry("2nd_ds", "2nd Data Source", page, sub_page) }}
{{ nav_entry("3rd_ds", "3rd Data Source", page, sub_page) }}
</ul>
</nav>
{% macro nav_entry(identifier, title, page_id, sub_page_id) %}
{% set attrs = {"class": "nav-selected"} if identifier == page_id else {} %}
<li{{ attrs | xmlattrs }}>{{ title }}
<ul class="nav nav-second-level">
<li{{ set_if_selected('1st_sub_entry', sub_page_id) }}>1st Sub-Entry</li>
{# Other set_if_selected calls left off for clarity) #}
<li>2nd Sub-Entry</li>
<li>3rd Sub-Entry</li>
</ul>
</li>
{% endmacro %}
{% macro set_if_selected(identifier, to_match) %}
{{ {"class": "nav-selected"} if identifier == to_match else {} | xmlattrs }}
{% endmacro %}
If all of these navigation entries are dynamic, then it gets even easier:
<nav class="top-navigation">
<ul class="nav nav-first-level">
{% for nav_item in navigation %}
{{ nav_entry(nav_item) }}
{% endfor %}
</ul>
</nav>
navigation could be as simple as a list of tuples:
# Tuples are in the form
# (Link Title, URL, Is Selected?, Sub Menu Items)
# And sub menu items are tuples in the form
# (Link Title, URL, Is Selected?)
navigation = [("1st Data Source", "/some/url", true, []),
("2nd Data Source", "/some/url/2", false, [("A", "/a", false)]),
("3rd Data Source", "/some/url/3", false, [("B", "/b", false),("C", "/c", false)])]
The updates to nav_entry are left as an exercise for the reader :wink:
I'm new to Django and I have a news post and on that same template I have a section on the right hand side displaying all of the latest posts. However when you are on one of the main news posts it also shows up in the 'latest news' tab on the right.
I'm pretty sure i need to use .exclude to filter out the one that is being displayed. However i don't know how django know which post is being displayed.
If you need to look at my code please ask. I'm only using basic models / views to output the data.
The line that shows the latest 3 posts:
other_news = NewsPost.objects.filter(live=True, categories__in=post.categories.all).distinct().order_by("-posted")[:3]
Code for the template:
<div class='related_article_wrapper'>
{% if other_news %}
{% for news in other_news %}
<div class="article_snipppet_wrap">
<img class="article_icon" src="/media/images/article_icon.png" alt="" />
<p>{{news.title}}</p>
<span>{{news.posted|date:"d/m/y"}} »</span>
</div>
{% endfor %}
<span><a style="text-decoration: none; href="/news-hub/news/">View all news »</a></span>
{% endif %}
</div>
Thanks,
Josh
Just add .exclude(id=post.id) to your filter chain:
other_news = NewsPost.objects.exclude(id=post.id).filter(live=True,
categories__in=post.categories.all).distinct().order_by("-posted")[:3]
exclude() takes arguments in the same format as filter(), it just does the opposite!