Django: how to get the second last object from database? - django

I have a model for news. I add news to the database with Django admin. Model Post consists of title, body and image.
On the main.html page of my project i have a carousel with 3 slides.
I already have some news in my database, and I want to display the last, the second last and so on images in that carousel.
My question is: what code should I add in html to display the last, the second last and the third last images?
<img src="???"> {# the last image #}
<img src="???"> {# the second last image #}
<img src="???"> {# the third last image #}

You can try like this:
posts= Post.objects.all().order_by('-id')
last_post = posts[0]
second_last_post = posts[1]
third_last_post = posts[2]
last_three_posts = posts[0:3]
But make sure to have atleast three posts or else it will throw index error

# views.py
from django.views.generic import TemplateView
class HomePageView(TemplateView):
template_name = 'home.html'
posts = Post.objects.all().order_by('-id')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context = {
'carousel_posts': self.posts[:3],
}
return context
Use this make a for loop over the carouser_posts keyword in your template and extract the information you need.
<div class="carousel-inner">
{% for post in carousel_posts %}
<div class="carousel-item active">
<img src="{{post.image}}">
<p>{{post.title}}"</p>
</div>
{% endfor %}
</div>
UPDATE
Answer to your update. Using context keyword carousel_posts provided by our HomePageView we can access post objects one by one using for loop.
In template, assuming that your Post model has an image field called image.
{% for post in carousel_posts %}
<img src="{{ post.image.url }}">
{% endfor %}

Related

data doesn't appear in my html page when i add new record - Django

when i add new record from admin panel it should appear in html page , but it doesn't do that
how to fix it
models.py :
class BestArticals(models.Model):
name = models.CharField(max_length=240)
url = models.URLField(default="",max_length=240)
image = models.ImageField(upload_to='images/',null=True, blank=True)
def get_image(self):
if self.image and hasattr(self.image, 'url'):
return self.image.url
else:
return '/path/to/default/image'
def __str__(self):
return self.name
views.py :
from .models import BestArticals
def Best_Articals(request):
best_posts = BestArticals.objects.all()
context = {'best_posts' : best_posts}
return render(request,'android/side_bar_good_posts.html',context=context)
html page :
{% for post in best_posts %}
<div class="card rounded mx-auto d-block" style="width: 18rem;margin-bottom:50px;border-color:#7952b3">
<div class="card-body" id="mobile_design_card">
<p class="card-text" id="mobile_design_card_name">{{ post.name }}</p>
</div>
<img src="{{ post.get_image }}" class="card-img-top" alt="..." height="290px" width="300px">
</div>
{% endfor %}
i didn't add Best_Articals in urls.py because i don't want create url for it , i just want show data in other html page from side_bar_good_posts.html
for example i add this line in other html page :
{% include 'android/side_bar_good_posts.html' %}
Based on your last comment... You should analyze how to works include tag and view function. Let me try to explain me, when you make request to some url, it calls to specific view function and the view return the processed data for this reason when you set url it works.
Include tag only add all text from in it in your file where you use include tag, for this when you add include 'android/side_bar_good_posts.html' only add plain text (html, css, js ) that contains android/side_bar_good_posts.html but in this point this file doesn't contains information about the post because your variable best_posts is empty, nothing call to your Best_Articals view to return best_post. You need to pass the additional context (best_post) to your template.
I.e. {% include "name_snippet.html" with person="Jane" greeting="Hello" %}
Or you could use context processor and then you can use {{best_post}} in all the templates.

Combining two queries from different application/models to display them on a single overview page

I have only recently started working with Django and was wondering how one would go around to combine two queries from different application/models and display them in a given overview page. I will display some non-functional pseudo-code below to illustrate what I am trying to do:
Index.html
Note that I added two seperate context_object_names here just to illustrate what I am trying to do (latest_news and latest_enzyme)
{% extends 'base.html' %}
{% block body %}
<div id="docs-content">
<div class="section" id="s-module-django.db.models.fields">
<div class="page-header text-primary">
<h3 class="info-header-blue-publication-small">Overview</h3>
</div>
<div>
<h3 class="info-header-blue-publication-tiny">Latest news:</h3>
</div>
{% if latest_news %}
{{ latest_news.news_text }}
{% else %}
<p>No recent news.</p>
{% endif %}
<div>
<h3 class="info-header-blue-publication-tiny">Latest enzyme:</h3>
</div>
{% if latest_enzyme %}
<ul>
<li>{{ latest_enzyme.barcode }}</li>
</ul>
{% else %}
<p>No enzymes are available.</p>
{% endif %}
</div>
</div>
{% endblock %}
Views.py
Note that this contains some commented lines that illustrate the method that I was trying but did not get working, as well as two seperate get_querysets to illustrate my intent.
from django.shortcuts import render from django.http import
HttpResponse from django.views import generic
from gts.models import Enzymes
from news.models import News
# Create your views here.
class IndexView(generic.ListView):
template_name = 'overview/index.html'
#context_object_name = 'latest_enzyme_news'
#def get_queryset(self):
# latest_enzyme = Enzymes.objects.order_by('-pub_date')[0]
# latest_news = News.objects.order_by('-pub_date')[0]
# return (latest_enzyme, latest_news)
context_object_name = 'latest_enzyme'
def get_queryset(self):
return Enzymes.objects.order_by('-pub_date')[0]
context_object_name = 'latest_news'
def get_queryset(self):
return News.objects.order_by('-pub_date')[0]
I have looked at similar questions, where they tried to combine multiple queries from multiple models of the same application (e.g. Display objects from different models at the same page according to their published date) but I would appreciate any hint or tip on what would be the 'best practice' for the situation that I described as I would wish to combine queries from different applications more often.
You don't want a ListView here at all. You're not listing things; you're just getting two separate items.
Rather, use a standard TemplateView and define get_context_data to return the specific items you want.
class IndexView(generic.TemplateView):
template_name = 'overview/index.html'
def get_context_data(self):
latest_enzyme = Enzymes.objects.order_by('-pub_date')[0]
latest_news = News.objects.order_by('-pub_date')[0]
return {'latest_enzyme': latest_enzyme, 'latest_news': latest_news}
(Note also, you could just as easily use a function-based view for this, since you are not really getting any value from the class.)

Django multi-level extends not appearing

With Django 1.10 I am building a blog/portfolio hybrid website. Besides Mysite, I have two apps, Blog and Portfolio. Within blog/templates/ I have an index.html that displays content from both Blog and Portfolio (the 15 most recent blog posts and 5 most recent portfolio projects).
So the index.html page looks like this:
http://imgur.com/y2UqBSS
As you can see data is not appearing. However, it does when I navigate to the Blog page and Portfolio page. For example, the Blog page:
http://imgur.com/7P922Ga
I am figuring that this issue is related to the mult-level extends that I have going on. Because the Blog and Portfolio pages both display content from the database, it makes me think that the models are O.K but something is up with the views. The index.html extends the base_generic.html template, and my recent_blog_posts.html and recent_portfolio_pieces.html extends the index.html.
I am not sure how to remedy this issue. Any suggestions what I'm doing wrong?
Project structure
mysite/
---blog/
------static/
---------css/
---------images/
------------blogpostimages/
------------favicon.ico
------templates/
---------blog/
------------blog_post.html
------------blog_list.html
------------recent_blog_posts.html
---------base_generic.html
---------index.html
---------bio.html
---------resume.html
------admin.py
------apps.py
------models.py
------tests.py
------urls.py
------views.py
---portfolio/
------static/
---------css/
---------images/
------------portfoliopieceimages/
------templates/
---------portfolio/
------------portfolio_piece.html
------------portfolio_list.html
------------recent_portfolio_pieces.html
------admin.py
------apps.py
------models.py
------tests.py
------urls.py
------views.py
---mysite/
------settings.py
------urls.py
------wsgi.py
manage.py
db.sqlite3
requirements.txt
blog/views.py
from django.shortcuts import render
from django.views import generic
# Create your views here.
from .models import Blog
def index(request):
"""
View function for home page of site.
"""
# Generate most recent blog post
title = Blog.objects.all()
post_date = Blog.objects.all()
get_absolute_url = Blog.objects.all()
# Render the HTML template index.html with the data in the context variable.
return render(
request,
'index.html',
context={'title': title,
'post_date': post_date,
'get_absolute_url': get_absolute_url,
}
)
def recent_blog_posts.html(request):
blog = Blog.objects.order_by('-post_date')[0:11]
return render(request, 'index.html', {'blog': blog})
class BlogListView(generic.ListView):
"""
Generic class-based view for a list of blog posts.
"""
model = Blog
paginate_by = 20
def get_queryset(self):
return Blog.objects.order_by('-post_date')
class BlogDetailView(generic.DetailView):
"""
Generic class-based detail view for a blog post.
"""
model = Blog
def bio(request):
return render(
request, 'bio.html'
)
def resume(request):
return render(
request, 'resume.html'
)
index.html
<div>
<h2>Recent Blog Posts</h2>
<div>
{% block blogs %}
{% if blog_list %}
{% for blog in blog_list %}
<article>
<header>
<h4><small>{{blog.post_date}} ยป </small>{{ blog.title }}</h4>
</header>
</article>
{% endfor %}
{% else %}
<p>Unfortunately, there are no blog posts yet.</p>
{% endif %}
</div>
{% endblock %}
</div>
<div>
<h2>Portfolio</h2>
{% if portfolio %}
{% for portfolio in portfolio %}
<div class="col-xs-12 col-sm-6 thumb">
<a class="thumbnail" href="{{ portfolio.get_absolute_url }}">
{% load static %}
<img class="img-responsive" src="{{ portfolio.cover_image }}" alt="">
<p>{{ portfolio.title }}</p>
<p>{{ portfolio.client_name }}</p>
</a>
</div>
{% endfor %}
{% else %}
<div>
<p>Unfortunately, there are no portfolio pieces yet.</p>
</div>
{% endif %}
You must use the variable pass to your context, in your template.
So you have to pass the variable blog_list to your context to iterate on it in your template.
Example below: (only for blog_list)
def index(request):
"""
View function for home page of site.
"""
blog_list = Blog.objects.all()
# Render the HTML template index.html with the data in the context variable.
return render(request, 'index.html', context={'blog_list': blog_list})
You need to pass the data to the template in the context. I don't really understand what you're trying to do in the index by setting and passing the variables in the context:
# Generate most recent blog post
title = Blog.objects.all()
post_date = Blog.objects.all()
get_absolute_url = Blog.objects.all()
Blog.objects.all() returns a queryset with all blog instances, not a title/post_date/get_absolute_url of a single blog instance.
In the template you refer to two context variables: blog_list and portfolio. You don't set the variables in the index. I would also avoid a statement like that:
{% for portfolio in portfolio %}
Don't use the same variable name as the variable you iterate over, change the latter to portfolio or portfolio_list.
To make it work you might try this:
index.py
def index(request):
blog_list = Blog.objects.all()
portfolio_list = Portfolio.objects.all()
return render(request, 'index.html',
context={'blog_list': blog_list, 'portfolio_list': portfolio_list}
)
In the index.html file change:
{% for portfolio in portfolio %}
to
{% for portfolio in portfolio_list %}

Simple vote button in Django

I'm an absolute beginner to django (and programming in general), I've tried the django Polls tutorial and all went well, however I am trying to get a minimal voting button to work. Basically I have set up a database with two columns, my models.py looks like this
from django.db import models
class Imgurl(models.Model):
urlvar = models.URLField(max_length=200)# a URL linking to an image
urlvote = models.IntegerField(default=0)# my intended vote count
def __unicode__(self):
return self.urlvar
I have made an input box where I can copy and paste an image url, this image then displays on a separate page(this works fine). What I want is to have a voting button next to each displayed image, where a user can click on the button (I am trying to use a submit button) and the number of votes will increase in the db(no redirecting to a new page, or anything fancy).
I think this is a trivial question and I am trying to learn the basics of POST and database handling in django (also, I have read the relevant chapters in the djangobook... maybe I'm just a little slow?)
my views looks like this
def urlvotes(request):
if request.method=='POST':
if 'voteup' in request.POST:
v=Imgurl(forloop.counter)
v.urlvote +=1
else:
pass
votetotal=v.urlvote # attempt to give the template some kind of context
return render_to_response('display.html', {'votetotal':votetotal}, context_instance=RequestContext(request))
and my template looks like this:
{% extends "base.html" %}
{% block head %}Image display{% endblock %}
{% block content1 %}
Home
{% if links %}
<ul>
{% for link in links %}
<li><img src="{{ link }}"></li>
<li><form action="{% url urlvotes %}" method="post">
{% csrf_token %}
<input type="submit" name="voteup" value='vote'/></p>
<p>{{votetotal}}</p>
</form></li>
{% endfor %}
</ul>
{% else %}
<p>No uploads.</p>
{% endif %}
{% endblock %}
when I run this, as is, I get a csrf verification failed error
Any help would be greatly appreciated
Try adding the #csrf_protect to your view
#csrf_protect
def urlvotes(request):
if request.method=='POST':
if 'voteup' in request.POST:
v=Imgurl(forloop.counter)
v.urlvote +=1
else:
pass
votetotal=v.urlvote # attempt to give the template some kind of context
return render_to_response('display.html', {'votetotal':votetotal}, context_instance=RequestContext(request))

Django - Simple custom template tag example

I have users, videos, topics, criterias and ratings
A video has a topic
A topic has criterias
A user can create a video for a given topic
A user can rate a video on each criterias given for the concerned topic.
You can see my original post Django - Rating Model Example DetailView Template to get details on the model used
I have extended a DetailView template based on the video model to put the list of ratings for the selected video for a given user as extra context.
class VideoFileDetailView(DetailView):
model = VideoFile
def get_context_data(self, **kwargs):
context = super(VideoFileDetailView, self).get_context_data(**kwargs)
context['rates'] = VideoRate.objects.filter(video=self.object, user=self.request.user)
return context
In the template pointed by the DetailView, I'd like to list the criterias of the video, and for each criteria display the current rating value form the user.
<div id="rating">
<ul>
{% for crit in videofile.topic.crits.all %}
<li>
{% for rate in rates %}
{% if rate.crit.id == crit.id %}
{{ rate.rate }}
{% endif %}
{% endfor %}
<div class="rateit"
data-rateit-value="{# The rating value #}"
data-rateit-ispreset="true"
crit-id="{{ crit.id }}"></div>
{{ crit }}
</li>
{% endfor %}
</ul>
</div>
(rateit is a jquery plugin that I use to draw pretty stars rating controls)
Actually I get my rating values here within the 2nd for but I'm sure there is a better way to do that. In fact, I'm still not sure about my model correctness.
Finally I'd like to replace {# The rating value #} by the rating value from rate for the current crit (in the loop). How can I do that ?
Here is my solution (based on a custom tag):
Firstly create the file structure. Go into the app directory where the tag is needed, and add these files:
templatetags
templatetags/__init__.py
templatetags/video_tags.py
The templatetags/video_tags.py file:
from django import template
register = template.Library()
#register.simple_tag
def get_rate(crit, rates):
return rates.get(crit=crit).rate
The template part, with our tag call:
{% load video_tags %}
<div id="rating">
<ul>
{% for crit in videofile.topic.crits.all %}
<li>
<div class="rateit"
data-rateit-value="{% get_rate crit rates %}"
data-rateit-ispreset="true"
crit-id="{{ crit.id }}"></div>
{{ crit }}
</li>
{% endfor %}
</ul>
</div>
Inline HTML in tag
If the HTML is small, this method is more convenient than creating a separate file.
This example factors out links to user profiles. The file templatetags/somemodule.py contains:
from django import template
from django.template import Template
register = template.Library()
#register.simple_tag(takes_context=True)
def user_link(context):
return Template('<a href="{% url \'user_detail\' ' +
'user.id %}">{{ user.username }}</a>').render(context)
Template#render already returns a safe string which is not XSS escaped. E.g. if we had done just:
return '<br>'
it would be escaped. You might also want to play with mark_safe.
You can make that tag available on all views with:
TEMPLATES = [
{
'OPTIONS': {
'builtins': [
'myprojectname.templatetags.somemodule',
in settings.py.
See also:
https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/
Rendering a template variable as HTML