I have integrated djangocms blog in my project. In homepage sidebar i want to display latest blog posts. Problem is, my homepage is django-cms page and i can't get blog post objects. urls.py:
urlpatterns = i18n_patterns('',
url(r'^admin/', include(admin.site.urls)),
.....
url(r'djangocms_blog/', include('djangocms_blog.urls', namespace='djangocms_blog')),
url(r'^', include('cms.urls')),
)
Somehow here in main.html i should be able to get blog records:
{% extends "base.html" %}
<nav class="secondary-menu">
<ul class="nav">
<!-- i need display them here -->
</ul>
</nav>
Is there any elegant way to do this?
Use either an assignment_tag or an inclusion_tag:
Templatetag
# templatetags/blog_tags.py
from django import template
from djangocms_blog.models import Post
register = template.Library()
#register.assignment_tag()
def latest_posts_as(limit=5):
return Post.objects.order_by('-date_published')[0:limit]
#register.inclusion_tag('latest_posts.html', takes_context=True)
def latest_posts_inline(context, limit=5):
qs = Post.objects.order_by('-date_published')[0:limit]
context.update({'posts': qs})
return context
Snippet for inclusion tag
<!-- latest_posts.html -->
{% for post in posts %}
<p>{{ post }}</p>
{% endfor %}
Your home/whatever template
<!-- your_template.html -->
{% load blog_tags %}
<div>
<!-- using assignment_tag -->
{% latest_posts_as limit=20 as posts %}
{% for post in posts %}
<p>{{ post }}</p>
{% endfor %}
<!-- using inclusion_tag -->
{% latest_posts_inline limit=10 %}
</div>
The limit is optional - but could be handy :)
Came up with other solution. Created new django-cms plugin:
class BlogLatestEntriesPluginNav(BlogLatestEntriesPlugin):
name = _('Navigition latest blog entries')
render_template = 'latest_entries_nav.html'
plugin_pool.register_plugin(BlogLatestEntriesPluginNav)
where BlogLatestEntriesPlugin is plugin from djangocms_blog app. And created new template 'latest_entries_nav.html'. Then in main.html
<ul class="nav">
{% placeholder "left_sidebar" %}
</ul>
created placeholder and added that plugin.
Related
I am using the "keyone" column in the database to filter entries. So far in the code i have written i am successfully able to render template with "keyone = 2" values. what should i write in a new template file, and how should i modify existing views.py so that when the template file renders it contains a list of links , each link for each value of "keyone" , when i click on the link say "keyone = 2", the selected entries should get rendered in home.html
models.py
# app/models.py
from django.db import models
from django.urls import reverse # new
class Post(models.Model):
text = models.TextField()
def __str__(self):
return self.text[:50]
keyone = models.IntegerField(default = '777')
def get_absolute_url(self): # new
return reverse('post_detail', args=[str(self.id)])
views.py
def HomePageView(request):
key2select = Post.objects.filter(keyone=2)
return render(request, 'home.html', {
'key2select': key2select,
})
home.html
<ul>
{% for post in key2select %}
<li>{{ post.keyone }}   {{ post.text }}</li>
{% endfor %}
</ul>
sample database
desired rendering
Firstly, we need to get all keyone values in the DB, to be passed to home.html.
Then in home.html, we need a navbar or somewhere else to put all these links which represent all the keyone values.
So the code would be like:
models.py
# app.models.py would remain the same
views.py
def homePageView(request, key):
key2select = Post.objects.filter(keyone=key)
keyones = Post.objects.distinct('keyone')
return render(request, 'home.html', {
'key2select': key2select,
'keyones': keyones
})
You can check the distinct() in the Django Docs to get distinct values of a column in DB
home.html
<!-- home.html -->
<nav>
<ul>
{% for key in keyones %}
<li>somthing {{key}} something</li>
{% endfor %}
</ul>
</nav>
...
<ul>
{% for post in key2select %}
<li>{{ post.keyone }}   {{ post.text }}</li>
{% endfor %}
</ul>
As we passed the key to the url in the nav link, we need to change the url pattern to catch this.
urls.py
urlpatterns =[
...
path('home/<int:key>/', views.homePageView, name='home')
...
]
May be I'm not understand you problem, if you'r looking for create a list of link code should be
<ul>
{% for post in key2select %}
<a href="{% url "post_detail" post.id %}"><li>{{ post.keyone }}   {{ post.text }}</li><a/>
{% endfor %}
</ul>
This will contain every post link with list item
thanks #sheng-zhuang for providing the solution. Here is the working code with some slight modifications for my benefit.
I created a new template select.html and here is the logic -
Views.py
class IndexView(TemplateView):
template_name = 'index.html'
def SelectView(request):
keyones = Post.objects.values_list('keyone',flat=True).distinct()
return render(request, 'select.html', {
'keyones': keyones
})
def HomePageView(request, key):
key2select = Post.objects.filter(keyone=key)
return render(request, 'home.html', {
'key2select': key2select,
})
index.html
<header>
Select<br />
Post
</header>
select.html
<nav>
<ul>
{% for key in keyones %}
<li>Keyone value = {{key}} </li>
{% endfor %}
</ul>
</nav>
home.html
<header>
Select<br />
Post
</header>
<br /><br /><br /><br />
<ul>
{% for post in key2select %}
<li>{{ post.keyone }}   {{ post.text }}</li>
{% endfor %}
</ul>
urls.py
path('', IndexView.as_view(), name='index'),
path('select/', SelectView, name='select'),
path('home/<int:key>/', HomePageView, name='home')
When I requested tag_list view the posts variable didn't list out the data.
And after changing its position above self_entries view, everything worked fine.
But now I cannot get self_entries view data.
What I am missing here?
After changing the position everything falls as expected but the view which lies at the bottom doesn't display the data at all.
more views at the top
#app.route('/entries')
#login_required
def list():
posts = models.Journal.select().order_by(models.Journal.created_at.desc())
return render_template("entries.html", posts=posts)
# This View Works as expected
#app.route('/entries/<username>')
#login_required
def self_entries(username):
posts = (models.Journal
.select(models.User, models.Journal)
.join(models.User)
.where(models.User.username**username)
.order_by(models.Journal.created_at.desc())
)
# for post in posts:
# print(post.title + str(post.created_at.date()) + post.tag)
return render_template("entries.html", posts=posts)
# This view doesn't... the page displays as empty
#app.route('/entries/<tag>')
#login_required
def tag_list(tag):
posts = (models.Journal
.select()
.where(models.Journal.tag == tag)
.order_by(models.Journal.created_at.desc())
)
return render_template("entries.html", posts=posts)
more views at the bottom
entries.html
{% extends "layout.html" %}
{% block content %}
<div>
<div>
<h1>{{ hi }}</h1>
{% for post in posts %}
<article>
<h2>{{ post.title }}</h2>
<time datetime="{{ post.created_at }}">{{ post.created_at.date() }}</time>
<h3><a href="{{ url_for('tag_list', tag=post.tag) }}" >{{ post.tag }}</a><h3>
</article>
{% endfor %}
</div>
</div>
{% endblock %}
Ok got it. Both the route below are using the similar API ie. '/entries/', so there is a conflict. so change either one.
#app.route('/entries/<username>')
#app.route('/entries/<tag>')
changed #app.route('/entries/<tag>') to #app.route('/entry/<tag>') it works.
I am trying to make a recent article list in the sidebar of my blog. So I make a tag in templatetags.
I use django1.8 and python2.7.
templatetags/blog_tags.py
from ..models import Article,Category
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
#register.simple_tag
def get_recent_articles(num=5):
return Article.objects.all()[:num]
base.html
{% load blog_tags %}
<!DOCTYPE html>
...
<div class="widget widget-recent-posts">
<h3 class="widget-title">recent</h3>
{% get_recent_articles as article_list %}
<ul>
{% for article in article_list %}
<li>
{{ article.title }}
</li>
{% endfor %}
</ul>
</div>
When I runserver,Template error,Traceback display the problem line is {% get_recent_articles as article_list %}
TemplateSyntaxError at /blog/index/
'get_recent_articles' received too many positional arguments
How do I solve this error? Please give me some advices.
Any help will be much appreciated.
The ability for simple tags to store their results in a variable was added in Django 1.9.
In previous versions, you should use the assignment_tag decorator instead.
I'm trying to follow the Simple Blog tutorial at Django By Example. I've managed to get as far as producing a site that loads correctly, but while the index view is loading find, and the links to the individual posts show up and appear to be formatted correctly, they point back to the index template so all that happens when you click on them is that it reloads the index view. I'm new to Django and the tutorial is sparse to say the least and not helped by the fact it's written for an old version of Django and I'm using 1.5. I've been staring at it all afternoon and I'm pretty lost.
Here's my urls.py
from django.conf.urls import patterns, url
from blog import views
urlpatterns = patterns('blog.views',
#index
(r"$", 'main'),
#ex: /1/
(r"^(\d+)/$", 'post'),
#ex: /add_comment/1/
(r"^add_comment/(\d+)/$", 'add_comment'),
)
my views.py
from blog.models import Post, PostAdmin, Comment, CommentAdmin
class CommentForm(ModelForm):
class Meta:
model = Comment
exclude = ["post"]
def main (request):
"""Main Listing."""
posts = Post.objects.all().order_by("-created")
paginator = Paginator(posts, 10)
try: page = int(request.GET.get("page", '1'))
except ValueError: page = 1
try:
posts = paginator.page(page)
except (InvalidPage, EmptyPage):
posts = patinator.page(paginator.num_pages)
return render_to_response("blog/list.html", dict(posts=posts, user=request.user))
def post (request, pk):
"""single post with comments and comment form"""
post = Post.objects.get(pk=int(pk))
comments = Comment.objects.filter(post=post)
d = dict(post=post, comments=comments, form=CommentForm(), user=request.user)
d.update(csrf(request))
return render_to_response("blog/post.html", d)
and the list.html that contains the links that aren't going anywhere!
{% extends "blog/bbase.html" %}
{% block content %}
<div class="main">
<!-- Posts -->
<ul>
{% for post in posts.object_list %}
<div class="title">{{ post.title }}</div>
<ul>
<div class="time">{{ post.created }}</div>
<div class="body">{{ post.body|linebreaks }}</div>
<div class="commentlink">Comments</div>
</ul>
{% endfor %}
</ul>
<!-- Next/Prev page links -->
{% if posts.object_list and posts.paginator.num_pages > 1 %}
<div class="pagination" style="margin-top: 20px; margin-left: -20px; ">
<span class="step-links">
{% if posts.has_previous %}
newer entries <<
{% endif %}
<span class="current">
Page {{ posts.number }} of {{ posts.paginator.num_pages }}
</span>
{% if posts.has_next %}
>> older entries
{% endif %}
</span>
</div>
{% endif %}
</div>
{% endblock %}
The Django URL resolver will return the first URL pattern that matches the incoming request. The regex for your 'main' view r"$" will match ANY incoming request since you are only looking for $ which is an end of string character.
You need to alter your 'main' URL regex to be r'^$'.
Alternatively, if you would like a catch-all view, you could move the 'main' view to the bottom of your URLs
I'm working on an Inclusion Tag. In the super shell, the tag returns the appropiate data set nevertheles, I dont see the inclusion template rendered on the calling template. I can only guess the inclusion template is in the wrong location. As of this moment, the template is at MYPROJECT/templates which is the ONLY folder in TEMPLATE_DIRS. Please help me figure out what am I doing wrong here. TIA!
MYPROJECT/newsroom/templatetags/blog_extras.py -> http://pastebin.com/ssuLuVUq
from mezzanine.blog.models import BlogPost
from django import template
register = template.Library()
#register.inclusion_tag('featured_posts.html')
def featured_posts_list():
"""
Return a set of blog posts whose featured_post=True.
"""
blog_posts = BlogPost.objects.published().select_related("user")
blog_posts = blog_posts.filter(featured_post=True)
# import pdb; pdb.set_trace()
return {'featured_posts_list': blog_posts}
MYPROJECT/templates/featured_posts.html -> http://pastebin.com/svyveqq3
{% load blog_tags keyword_tags i18n future %}
Meant to be the the infamous "Featured Posts" Section!
{{ featured_posts_list.count }}
<ul>
{% for featured_post in featured_posts_list %}
<li> {{ featured_post.title }} </li>
{% endfor %}
</ul>
MYPROJECT/settings.py -> pastebin.com/Ed53qp5z
MYPROJECT/templates/blog/blog_post_list.html -> pastebin.com/tJedXjnT
As #Victor Castillo Torres said, you need to change the name of the tag you're loading, which will fix that aspect of your template tag. However, even though they are in different namespaces, I would still change the name of the context variable your tag returns just for sanity:
#register.inclusion_tag('featured_posts.html')
def featured_posts_list():
blog_posts = BlogPost.objects.published().filter(
featured_post=True).select_related("user")
return {'blog_posts': blog_posts}
Then in your template:
{{ blog_posts.count }}
<ul>
{% for blog_post in blog_posts %}
<li>{{ blog_post.title }} </li>
{% endfor %}
</ul>
And finally, in your main template:
{% load blog_extras keyword_tags i18n_future %}
...
{% featured_posts_list %}