October CMS (Rainlab Blog) - Next and Prev Post link from same category - blogs

I have a blog post page where I'm using the category as a hardcoded parameter in url.
The url is like
url = "/category1/:slug"
I'm using blogPost component in this layout.
I can get the nextPost and prevPost link using the following code in template
{% set nextPost = blogPost.post.nextPost %}
{% set prevPost = blogPost.post.previousPost %}
But I want to constraint nextPost and prevPost to be from same category as blogPost.post i.e. category1
blogPost.post belogs to only one category
I've checked that the Post model has a method scopeFilterCategories
but I'm not sure how to use it or if it serves the same purpose.
Code
This is the configuration part
title = "Category1 post"
url = "/category1/:slug"
layout = "default"
is_hidden = 0
robot_index = "index"
robot_follow = "follow"
[blogPost]
slug = "{{ :slug }}"
categoryPage = "category1"

It seems Thye are not Providing that Out of the box
I have created snippets which can do that work.
In you page's code block add this code snippet [ next previous works based on published_at field (Published on in form) ]
public function nextPost($post) {
// get current cats
$postCats = $post->categories->pluck('id')->toArray();
// Here you need to pass it as we are
// hardcoding category slug in URL so we have no data of category
// IF YOU DONT WANT CAT COME FROM POST
// YOU CAN HARD CODE THEM $postCats = ['2']
// here 2 is id of category
// use this cats to scope
$nextPost = $post->isPublished()->applySibling(-1)
->FilterCategories($postCats)->first();
// check if next is not availabe then return false
if(!$nextPost) {
return false;
}
// create page link here same page
$postPage = $this->page->getBaseFileName();
// set URl so we can direct access .url
$nextPost->setUrl($postPage, $this->controller);
// set Cat URl so we can use it directly if needed
$nextPost->categories->each(function($category) {
$category->setUrl($this->categoryPage, $this->controller);
});
return $nextPost;
}
public function previousPost($post) {
// get current cats
$postCats = $post->categories->pluck('id')->toArray();
// IF YOU DONT WANT CAT COME FROM POST
// YOU CAN HARD CODE THEM $postCats = ['2']
// here 2 is id of category
// use this cats to scope
$prevPost = $post->isPublished()->applySibling(1)
->FilterCategories($postCats)->first();
// check if nprevious ext is not availabe then return false
if(!$prevPost) {
return false;
}
// create page link here same page
$postPage = $this->page->getBaseFileName();
// set URl so we can direct access .url
$prevPost->setUrl($postPage, $this->controller);
// set Cat URl so we can use it directly if needed
$prevPost->categories->each(function($category) {
$category->setUrl($this->categoryPage, $this->controller);
});
return $prevPost;
}
In Markup area you can add this code.
{% component 'blogPost' %}
{% set nextPostRecord = this.controller.pageObject.nextPost(blogPost.post) %}
{% set previousPostRecord = this.controller.pageObject.previousPost(blogPost.post) %}
{% if previousPostRecord %}
Previous
{% endif %}
{% if nextPostRecord %}
Next
{% endif %}
This will respect category and show only that category posts
If any doubt please comment.

Related

Is there a way to display a jinja variable name instead of it's value?

I'm writing a program in flask currently and I'm trying to see if I can display the name of a Jinja variable instead of the value it holds. For example:
{% set x = 0 %}
<button onclick="myFunction({{ x }})>
I'm trying to pass the variable into a javascript function but having the HTML show myFunction(x) instead of myFunction(0). Is there any way to do this?
Try:
for(var key in objects) {
var value = objects[key];
}

Django not recognizing user form email verification link:

I've spent the last week on this like 20 hours and can't figure it out. This is my very first Django application.
I have tested the 'urlsafe_base64_encode(force_bytes(user.pk))' in shell and it works to pass the user's 'uid', however it does not work in the application itself. I get that the 'activation link is invalid' for all links even though the link passed the correct primary key, I'm not sure what is going wrong.
Please help.
views.py/registration page
from_email, subject = 'domain <info#domain>', 'Email verification'
htmly = get_template('activation_email_template.html')
username = user.username
message = render_to_string('activation_email.html', {
'user':user,
'token':account_activation_token.make_token(user),
'uid':urlsafe_base64_encode(force_bytes(user.pk)),
})
d = {'username': username, 'url':reverse('activate',
kwargs={
'token':account_activation_token.make_token(user),
'uidb64':urlsafe_base64_encode(force_bytes(user.uid))
})}
html_content = htmly.render(d)
msg = EmailMultiAlternatives(subject, message, from_email,[user.email])
msg.attach_alternative(html_content, "text/html")
msg.send()
here is my activate/views.py:
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
...
else:
return HttpResponse('Activation link is invalid!')
For some reason I'm getting 'Activation Link is invalid' every time I try this. I know it's sending the right PK, because I can clink on the url and the url is correct with the correctly encoded pk. However, the activate view does not recognize this pk.
here is my activation_email.html:
{% autoescape off %}
Hi {{ user.username }},
Thanks for creating an account. Please click on the link to confirm your registration,
http://domain{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}
This is the activation_email_template:
<h3>Hi <strong>{{ username }}</strong>,</h3>
<p>Thanks for creating an account. Please click on the following link to confirm your registration:</p>
<a style="background-color: #f79407 ;padding: 10px 15px; text-decoration: none;color: #ffffff;text-transform: uppercase;font-size: 15px;" href="https://domain{{ url }}">Email Activation</a>
Please help!
Tried this to get at errors in activation link, but still just get activation link is invalid:
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except TypeError:
print('typerror')
user=None
except ValueError:
print('valueerror')
user=None
except OverflowError:
print('OverflowError')
user=None
except User.DoesNotExist:
print('user.DoesNotExist')
user=None
if user is not None and account_activation_token.check_token(user, token):
....
else:
raise ValidationError('user is none')

Django dynamic table with AJAX

This is the second question in the row about my Django project. The code I use here has parts copied from this question:Stack Overflow
What I aim to achieve is a dynamic table, that loops through objects in a list(currently the interval between records is 3 seconds). Let's say I have 21 records. The table first displays records of 1 to 10, on the displaykala.html table. Then it replaces only the table content with records of 11 to 20(with AJAX, without page refresh. The new contents come from get_more_tables_kala.html, and those table rows coming from there, are appended to the displaykala.html table).
At no point should the table be empty (UNLESS there is simply no objects to display).
Finally, the contents of 11-20 are replaced with contents of 21-30. In this case, only one row is displayed.
Basicly it always displays first ten records(even if there is only one). Then the code increments the startindex and endindex of the rows, and checks if there is records between those. If there is more than 10 records, it will empty the table and instantly load up the next records (as long as there is even 1 record). Else, the program should wait X amount of seconds, until checking again.
The code has been going through various experimentations, I'm sorry for any dumb coding. I'm still learning Django and AJAX.
There is a few problems though, but let's focus on the main one
When the displaykala.html is loaded, the table is displayed empty first, for 3 seconds. I know this is because the code loads the empty displaykala.html table.
If I were to set in views that displaykala.html table should display rows 1 to 10 by default, I run into a rendering problem if there is more than 10 rows.
Those rows are loaded from the get_more_tables_kala.html, but when the code is supposed to switch back to displaykala.html, I'm either forced to reload the page (which is not an option due to network traffic increase), or return a new render with displaykala.html as a parameter, which causes the page to create a "copy" of itself, in the place where the table rows are supposed to be.
What I want is the program to switch between the records, without diplaying empty page in between.
I am open to any kind of optimizations or different ideas, as long as they're somewhat simple to understand. I know that this code is rubbish. I'm just trying to get it to work.
I must have missed something vital to tell you, please comment below if you need more info.
EDIT: Also, when I look at the django server console, the three tables (1-10, 11-20(only two records) and the empty one) produce these rows:
[14/Dec/2017 12:33:22] "GET /user/get_more_tables_k HTTP/1.1" 200 2222
[14/Dec/2017 12:33:24] "GET /user/get_more_tables_k HTTP/1.1" 200 439
[14/Dec/2017 12:33:27] "GET /user/get_more_tables_k HTTP/1.1" 200 1
My code runs between views.py, js_kala.html, displaykala.html and get_more_tables_kala.html.
views.py
from django.shortcuts import render, redirect
from userside.models import Kala
from django.contrib.auth.decorators import login_required
from django.db import connection
#login_required
def displaykala(request):
return render(request, 'displaykala.html')
#login_required
def get_more_tables_kala(request):
startind = request.session.get('startind')
if not startind:
startind = 0
request.session['startind'] = startind
endind = request.session.get('endind')
if not endind:
endind = 10
request.session['endind'] = endind
kalat = Kala.objects.filter(rivinro__gt=startind, rivinro__lte=endind)
count = kalat.count()
if count == 0:
request.session['startind'] = 0
request.session['endind'] = 10
kalat = Kala.objects.filter(rivinro__gt=startind, rivinro__lte=endind)
return render(request, 'get_more_tables_kala.html', {'kalat': kalat})
else:
request.session['startind'] += 10
request.session['endind'] += 10
kalat = Kala.objects.filter(rivinro__gt=startind, rivinro__lte=endind)
return render(request, 'get_more_tables_kala.html', {'kalat': kalat})
js_kala.html
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"> </script>
<script>
var append_increment = 0;
setInterval(function() {
$.ajax({
type: "GET",
url: "{% url 'get_more_tables_kala' %}", // URL to your view that serves new info
data: {'append_increment': append_increment}
})
.done(function(response) {
$('#_appendHere_kala').html('');
$('#_appendHere_kala').append(response);
append_increment += 10;
});
}, 3000)
</script>
displaykala.html
<html>
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
{% load static %}
{% include 'loginbar.html' %}
<head>
<link rel="stylesheet" type="text/css" href="{% get_static_prefix %}css/style.css">
<title>Display</title>
</head>
<body>
<h1>Display</h1>
<table>
<tr>
<th>Rivinumero</th>
<th>Tuote</th>
<th>Latinankielinen nimi</th>
<th>Pyyntialue</th>
<th>Pyyntipäivä</th>
<th>Tuotantotapa</th>
<th>Pyydystyyppi</th>
</tr>
</table>
<table id="_appendHere_kala" class="table table-striped table-condensed">
<thead>
</thead>
{% include 'js_kala.html' %}
{% for kala in kalat %}
<tr>
<tbody id="tbody">
<td>{{kala.rivinro}}</td>
<td>{{kala.tuote}}</td>
<td>{{kala.latinalainen_nimi}}</td>
<td>{{kala.pyyntialue}}</td>
<td>{{kala.pyyntipaiva|date:"d.m.Y" }}</td>
<td>{{kala.tuotantotapa}}</td>
<td>{{kala.pyydystyyppi}}</td>
</tbody>
</tr>
{% endfor %}
</table>
</body>
</html>
get_more_tables_kala.html
{% load static %}
{% for kala in kalat %}
<tbody id='tbody'>
<tr>
<td>{{kala.rivinro}}</td>
<td>{{kala.tuote}}</td>
<td>{{kala.latinalainen_nimi}}</td>
<td>{{kala.pyyntialue}}</td>
<td>{{kala.pyyntipaiva|date:"d.m.Y" }}</td>
<td>{{kala.tuotantotapa}}</td>
<td>{{kala.pyydystyyppi}}</td>
</tr>
</tbody>
{% endfor %}
You should fetch data from database in "displaykala" view and throw the data into the template file. The startind should be 0 and endind should be 9 because you are fetching 10 records only.
For the empty table problem, it seems that the setInterval() function would cause the table to be empty for 3 seconds. After calling the setInterval(), it will wait for a period of time (3 seconds in this case) before executing the process. Which means this function makes your program cannot be executed immediately.
Here is the process workflow:
Wait for 3 seconds
Run AJAX
Wait for 3 seconds
Run AJAX
Again and again
Which means you should execute the AJAX process once before calling the setInterval().
--Edit--
After asking so many questions, I've found something that might also cause the empty table problem.
In this part,
if count == 0:
request.session['startind'] = 0
request.session['endind'] = 10
kalat = Kala.objects.filter(rivinro__gt=startind, rivinro__lte=endind)
return render(request, 'get_more_tables_kala.html', {'kalat': kalat})
You still use startind and endind (which are the same arguments used in previous filtering statement) to do filter when the system cannot find any data in the filtering. This makes your system prints nothing.
However, from your code, I cannot see why your system finds nothing from the database in every time you started opening the page. You will have to open debug mode of IDE and DevTools of web browser to see what happens with the session and Python variables.
Solved for now, got help from elsewhere with a brand new solution.

Jekyll, how to display images in a folder by date?

I am creating a website gallery. There is such a structure:
my site
artworks
caty1
caty2
It is necessary to display the photos in page of a given category (caty2 or caty1) by creation date.
Actually, how to realize using Jekyll and Liqiud?
Or is there a more appropriate structure for this?
with liquid you can filter/sort an array but any of its elements attribute that you want.
in your case you need to create datafile (in yml, csv or json) representing a collection of photos, and each photo should have a date attribute (along with a name, src, ...).
then in the layout that generate a caty page you'll have some thing like:
{% assign sorted-photos = site.data.photos | sort: 'date' %}
<ul> <!-- list of sorted photos -->
{% for photo in photos %}
<li> <img src={{photo.src}} alt={{photo.name}}></li>
{% endfor %}
</ul>
the photos collection would be a photos.yml file located in _data directory with a structure similar to:
- src = assets/img/p1.jpg
date = 10-01-2017
name = cute cat
category = cats # if you need to filter by category ?
- src = assets/img/p2.jpg
date = 12-01-2017
name = grumpy cat-2
category = cats
- src = assets/img/p3.jpg
date = 10-11-2016
name = cool dog
category = dogs

How can I reset an increment?

In some template I'm iterating some data using a for loop which is part of some other parent for loop.
Using some conditions, I need to increment a counter for each iteration of the inner for loop, and reset it whenever the template goes to the next outer for loop iteration.
I'm using {% increment someVar %}, but I can't figure out how to reset someVar to 0.
Is this ever possible?
Use {% assign someVar = 0 %}, increment with {% assign someVar = someVar | plus: 1 %}.
The correct way is to use {% assign someVar = 0 %} above the loop, and then increment it with {% assign someVar = someVar | plus: 1 %}.
I think David's answer just has a typo leading it someVar always being equal to 1, but otherwise was right on the money.