I'm having a little conundrum with sorting some items. I have a field called featured thats a boolean. I'm trying to display the featured coins first and then the remaining will be sorted by a different metric. In this code im using pub_date.
However, when I put an if statement in my template for the featured items it's still showing those that are set to false as well. I'll post code below.
index.html loops and if's
{% if featured_coins_list %}
{% for coin in featured_coins_list %}
<div class="large-6 medium-6 cell">
<h2>{{ coin.name }}</h2>
<p>Ticker: {{ coin.ticker }}</p>
<p>{{ coin.summary }}</p>
More Info</strong>
</div>
{% endfor %}
{% endif %}
{% if latest_coins_list %}
{% for coin in latest_coins_list %}
<div class="large-6 medium-6 cell">
<h2>{{ coin.name }}</h2>
<p>Ticker: {{ coin.ticker }}</p>
<p>{{ coin.summary }}</p>
More Info</strong>
</div>
{% endfor %}
</div>
{% else %}
<p>No coins are available.</p>
{% endif %}
views.py for index
def index(request):
featured_coins_list = Coin.objects.order_by('-featured')[:4]
latest_coins_list = Coin.objects.order_by('-pub_date')[:8]
context = {'featured_coins_list': featured_coins_list,
'latest_coins_list': latest_coins_list}
return render(request, 'coins/index.html', context)
models.py
class Coin(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
ticker = models.CharField(max_length=5)
featured = models.BooleanField(default=False)
logo = models.ImageField(upload_to='uploads/', verbose_name='image')
website = models.URLField(max_length=200, default="https://example.com/")
reddit = models.URLField(max_length=200, default="https://reddit.com/r/")
twitter = models.URLField(max_length=200, default="https://twitter.com/")
summary = models.CharField(max_length=500, blank=True)
description = models.TextField()
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.ticker
def is_featured(self):
return self.featured
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
How should I go about listing the featured coins that are set to true first and then display the remaining items after?
You need to filter for featured=True in your queryset.
def index(request):
featured_coins_list = Coin.objects.filter(featured=True).order_by('-featured')[:4]
latest_coins_list = Coin.objects.order_by('-pub_date')[:8]
context = {'featured_coins_list': featured_coins_list,
'latest_coins_list': latest_coins_list}
return render(request, 'coins/index.html', context)
Related
I need to limit the number of posts in Django queries. I have tried to add a min and max but nothing seemed to have worked. I have added home.html into the code.
Example: I should only have the 15 most recent posts in my blog. The rest can be seen by clicking on the category button.
Home.html:
{% extends 'base.html' %}
{% block content %}
<h1>Posts</h1>
<ul>
{% for post in object_list %}
<li>{{post.title}}
<style>
a {
text-transform: capitalize;
}
</style>
- {{ post.category }} - <a href="{% url 'show_profile_page' post.author.profile.id %}">{{ post.author.first_name }}
{{ post.author.last_name }}</a> - {{ post.post_date }} <small>
{% if user.is_authenticated %}
{% if user.id == post.author.id %}
- (Edit)
(Delete)
{% elif user.id == 1 %}
- (Edit)
(Delete)
{% endif %}
{% endif %}
</small><br/>
{{ post.snippet }}</li>
{% endfor %}
</ul>
{% endblock %}
view.py:
class HomeView(ListView):
model = Post
template_name = 'home.html'
ordering = ['-id']
def get_context_data(self, *args, **kwargs):
cat_menu = Category.objects.all()
context = super(HomeView, self).get_context_data(*args,**kwargs)
context["cat_menu"] = cat_menu
return context
models.py:
class Post(models.Model):
title = models.CharField(max_length=255)
header_image = models.ImageField(null=True, blank=True, upload_to='images/')
title_tag = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = RichTextField(blank=True, null=True)
post_date = models.DateField(auto_now_add=True)
category = models.CharField(max_length=255, default='intro')
snippet = models.CharField(max_length=255)
likes = models.ManyToManyField(User, related_name='post_likes')
dislikes = models.ManyToManyField(User, related_name='post_dislikes')
I think you have another template for displaying categorised objects when you click category button. As you said
"I should only have the 15 most recent posts in my blog. The rest can
be seen by clicking on the category button."
In this case you can use a simple hack to display most recent posts from your table.
query all objects in descending order in views
all_objs = Post.objects.all().order_by('-id')
Then use {% if forloop.counter <= 15 %} to display last 15 items only. as follow.
templates
{% for post in object_list %}
{% if forloop.counter <= 15 %}
<h4>{{obj}} #or anything really that is meant to be shown on the home page.</h4>
{% endif %}
{% endfor %}
You can do something like this:
def get_context_data(self, *args, **kwargs):
context = super(HomeView, self).get_context_data(*args,**kwargs)
context["cat_menu"] = Category.objects.all()
context["most_recent_posts"] = Post.objects.filter(author=self.request.user).order_by('-post_date')[:15]
return context
This will get the 15 most recent posts authored by the current user, ordered by the date it was posted.
Then just handle displaying this in home.html for example:
<ul>
{% for p in most_recent_posts %}
<li>{{ p.title }}</li>
{% endfor %}
</ul>
Just limit your query to the latest 15 entries sorted by post_date:
cat_menu = Category.objects.latest("post_date")[:15]
https://docs.djangoproject.com/en/3.2/topics/pagination/
The best way is Django Pagintion.
{% for contact in page_obj %}
{# Each "contact" is a Contact model object. #}
{{ contact.full_name|upper }}<br>
...
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
from django.core.paginator import Paginator
from django.shortcuts import render
from myapp.models import Contact
def listing(request):
contact_list = Contact.objects.all()
paginator = Paginator(contact_list, 25) # Show 25 contacts per page.
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'list.html', {'page_obj': page_obj})
you can use Django pagination api . Manage your data through page number. Initially pass 1 and after that page number given by pagination.
paginator = Paginator(yourquerysetdata, 20)
page_num = request.data.get('page')
result = yourSerializerName(paginator.get_page(page_num) many=True).data
try:
page = paginator.page(page_num)
except:
page = paginator.page(1)
count = paginator.num_pages
resultobj = paginator.get_page(page_num)
has_prev = resultobj.has_previous()
has_next = resultobj.has_next()
page_range = resultobj.paginator.page_range.stop - 1
if has_prev:
prev_page_no = resultobj.previous_page_number()
else:
prev_page_no = 0
if has_next:
next_page_no = resultobj.next_page_number()
else:
next_page_no = None
context = dict()
context['page'] = page.number
context['page_no'] = count
It is very simple. You just have to modify the query that you are using to fetch the posts.
In the get_context_data() method, replace cat_menu = Category.objects.all() with cat_menu = Category.objects.all().order_by('-post_date')[:15]. This will limit the number of results to 15 most recent objects.
For more understanding, you can take a look at the official Django docs for Limiting QuerySets.
I've been able to display all offices in an election, but have been unable to display all candidates in an office on the same page
models.py
class Election(models.Model):
name = models.CharField(max_length = 30)
slug = models.SlugField(max_length = 250, null = False, unique = True)
class Office(models.Model):
election = models.ForeignKey(Election, on_delete=models.CASCADE, default=None)
name = models.CharField(max_length = 30)
class Candidate(models.Model):
office = models.ForeignKey(Office, on_delete=models.CASCADE, default=None)
name = models.CharField(max_length = 30)
views.py
def poll(request, id):
context = {
'election' : Election.objects.get(pk=id),
'off' : Office.objects.all()
}
return render(request, 'poll.html', context)
poll.html
{% for office in election.office_set.all %}
<div class="text-center">
<h3>{{ office.name }}</h3>
{% for candidate in off.candidate_set.all %}
<h5>{{ candidate.name }}</h5>
{% endfor %}
</div>
{% endfor %}
In your first line of poll.html, you call "office" from the queryset "election.office_set.all"
Therefore, when you call a subquery of that QS, you have to reference the original name, ie: office, rather than off.
Your final code should look like this:
poll.html
{% for office in election.office_set.all %}
<div class="text-center">
<h3>{{ office.name }}</h3>
{% for candidate in office.candidate_set.all %}
<h5>{{ candidate.name }}</h5>
{% endfor %}
</div>
{% endfor %}
You also don't need the line
'off' : Office.objects.all()
in your Views.py.
I'm new to Django and I'ma building a basic blog application.
I cant show manytomany field (in tags) and a foreignkey field (comments) in my details page.
models.py
class BlogContent(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=200)
content = models.TextField()
date_published = models.DateField(auto_now=True)
image = models.ImageField(upload_to='media/')
def __str__(self):
return self.title
class TagName(models.Model):
tag = models.ManyToManyField(BlogContent, null=True)
name = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return self.name
class Comment(models.Model):
comt_text = models.TextField()
comments = models.ForeignKey(BlogContent, on_delete=models.CASCADE)
date_published = models.DateField(auto_now=True)
name = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return self.name
views.py
def details(request, blogcontent_id):
data_blog = get_object_or_404(BlogContent, pk=blogcontent_id)
data_tag = get_object_or_404(TagName, pk=blogcontent_id)
data_comment = Comment.objects.select_related()
return render(request, 'details.html',
{'data_blog': data_blog, 'data_tag':data_tag, 'data_comment':data_comment})
details.html
{% extends 'base.html' %}
{% block body_base %}
<img class="card-img-top img-responsive" src={{ data_blog.image.url }} alt="Card image cap">
<h2 class="blog-post-title">{{ data_blog.title }}</h2>
<p class="blog-post-meta">{{ data_blog.date_published }} {{ data_blog.author }}</p>
<p>{{ data_blog.content }}</p>
{% endblock %}
how do i show foreignkey and manaytomany fieds after this?
TBH this is much easier if you use class based views.
The view would simply be:
class BlogContentDetail (DetailView):
model = BlogContent
The url call would be url(r'^blog-detail/(?P<pk>\d+)/$, BlogContentDetail.as_view(), name="blog_detail")
Your html file should be called blogcontent_detail.html and held within the app subfolder in the templates folder
The template would then be:
{% extends 'base.html' %}
{% block body_base %}
<img class="card-img-top img-responsive" src={{ object.image.url }} alt="Card image cap">
<h2 class="blog-post-title">{{ object.title }}</h2>
<p class="blog-post-meta">{{ object.date_published }} {{ object.author }}</p>
<p>{{ object.content }}</p>
{% for tag in object.tags_set.all %}{{ tag }}{% endfor %}
{% endblock %}
You can iterate the ManyToMany Field in this way
{% for tags in data_tag.tag.all %}
<p > {{tags}} </ p>
{% endfor %}
For foreign key
{{data_comment.comments}}
I'm working on a Django blog, and having implemented category for detail page. I've stumbled upon an issue.
I want to display some categories of a product by using many to many field, I use the following code.
This my model.py file
from django.db import models
from django.urls import reverse
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('myshop:product_list_by_category', args=[self.slug])
class Product(models.Model):
category = models.ManyToManyField(Category)
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=200)
image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField()
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('myshop:product_detail', args=[self.slug])
This is views.py file
from django.shortcuts import render, get_object_or_404
from .models import Category, Product
# Create your views here.
def product_list(request, category_slug=None):
category = None
categories = Category.objects.all()
products = Product.objects.filter(available=True)
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
products = products.filter(category=category)
return render(request, 'shop/product/list.html', {'category': category, 'categories': categories, 'products': products})
def product_detail(request, product_slug):
product = get_object_or_404(Product, slug=product_slug, available=True)
category = product.category.filter(is_active=True)
return render(request, 'shop/product/detail.html', {'product': product}, {'category': category})
and this is for detail.html page file
{% extends "shop/base.html" %}
{% load static %}
{% block title %}
{% if category %}{{ category.title }}{% else %}Products{% endif %}
{% endblock %}
{% block content %}
<div class="product-detail">
<img src="{% if product.image %}{{ product.image.url }}{% else %}{% static "img/no_image.png" %}{% endif %}">
<h1>{{ product.name }}</h1>
{% for category in category %}{{ category.name }}{% if not forloop.last %}, {% endif %}
{% endfor %}
<p class="price">${{ product.price }}</p>
{{ product.description|linebreaks }}
</div>
{% endblock %}
I followed the tutorial from Django by Example book.
in the book includes a code to display just one category of each product with the following code
<a href="{{ product.category.get_absolute_url }}">{{ product.
category }}</a>
and I change it to code like above in detail.html file.
Thank you for the help
Try
{% for category in product.category.all %}
{{ category }}
{% endfor %}
I have two models news and category, and in news I have foreignkey of category. I know how to display news with same category in a single template. but furthermore, in my home page I'm trying to display featured news of each category. this is where I'm having problem.
this is my models.py
class News(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
category = models.ForeignKey("Tag")
active = models.BooleanField(default=True)
featured = models.BooleanField(default=False)
top = models.BooleanField(default=False)
slug = models.CharField(max_length=255, unique=True)
featuredInCat = models.BooleanField(default=False)
objects = StoryManager()
class NewsQueryset(models.query.QuerySet):
def active(self):
return self.filter(active=True)
def featuredInCat(self):
return self.filter(featuredInCat=True)
class NewsManager(models.Manager):
def get_queryset(self):
return NewsQueryset(self.model, using=self._db)
def get_featuredInCat(self):
return self.get_queryset().active().featuredInCat()
def all(self):
return self.get_queryset().active()
class Category(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(max_length=5000, null=True, blank=True)
In views.py
def category_list(request):
categoryList = NewsCategory.objects.all()
featuredInCat = News.objects.get_featuredInCat()
context = {
"featuredInCat":featuredInCat
"categoryList":categoryList,
}
return render(request,"news/category_list.html", context)
In my template
{% for category in categoryList %}
<div class='col-sm-4'>
<div id="container">{{category.title}}</h1>
<ul>
{% for x in featuredInCat %}
{{x.title}}</li>
{% endfor %}
</ul>
</div>
<hr>
</div>
{% endfor %}
then this shows the featuredInCat in every category where featuredInCat should be shown only in its Category section.
how do I fix this?
Take a look at the built-in regroup template tag of django. You will need to change your template to something like this:
{% regroup featuredInCat by category as news_list %}
<ul>
{% for news in news_list %}
<li>{{ news.grouper.title }}
<ul>
{% for item in news.list %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
You can change your for loop to iterate over the correct objects
{% for x in category.news_set.get_featuredInCat %}
You won't need the context variable anymore