I have no idea if this question make much sense or not but i am so confused about it. I have a post list view and it is rendering some of the post here.
My question is how can I split the sections of the page.something like this.
what should be the approach of making this kind of view.
this is my posts view.py
posts/view.py
class PostListView(ListView):
model = Post
template_name = 'posts/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
def get_queryset(self):
if not self.request.user.is_authenticated:
return Post.objects.all()[:10]
else :
return super().get_queryset()
posts/models.py
from django.db import models
from django.utils import timezone
from slugger import AutoSlugField
from django.contrib.auth.models import User
from django.urls import reverse
# Create your models here.
def upload_location(instance, filename):
return "%s/%s" %(instance.slug, filename)
class Category(models.Model):
title = models.CharField(max_length= 60)
slug = AutoSlugField(populate_from='title')
parent = models.ForeignKey('self',blank=True, null=True ,related_name='children',on_delete=models.CASCADE)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return self.title
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=120)
slug = AutoSlugField(populate_from='title')
image = models.ImageField(
upload_to=upload_location,
null=True,
blank=True,
)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self, slug=None):
return reverse("posts-detail", kwargs={"slug": self.slug})
You have posts assigned to categories. Each post could be assigned only to one category (since you have FK from Post to Category). And you want to display all categories and 10 latest posts under each one.
I see several ways of how to solve that. The easiest one is to extend Category model with property, containing the queryset to retrieve related posts in the way you want them for front page.
class Post(models.Model):
title = models.CharField(max_length=255)
category = models.ForeignKey('Category', on_delete=models.CASCADE, related_name='posts')
date_posted = models.DateTimeField(default=timezone.now)
class Category(models.Model):
title = models.CharField(max_length=255)
#property
def posts_for_frontpage(self):
return self.posts.order_by('-date_posted')[:10]
class FrontpageView(ListView):
model = Category
template_name = 'frontpage.html'
context_object_name = 'categories'
def get_queryset(self):
# select some categories for frontpage
# all by default
return Category.objects.all()
and then in template
{% for category in categories %}
<h1>{{ category.title }}</h1>
<hr />
{% for post in category.posts_for_frontpage %}
<h4>{{ post.title }}</h4>
{% endfor %}
<br />
<br />
{% endfor %}
You could also play with select_related to reduce number of queries and with annotate to get all related posts.
Related
I wanted to categorize my site content. Show the category titles in the menu and the contents of each category in the body. I have used these codes.
#urls
path('category/<slug:slug>', views.category, name="category")
#views
def category(request, slug):
context = {
"categorys": get_object_or_404(Category, slug=slug, status=True)
}
return render(request, "blog/category.html", context)
#models
class PostManager(models.Manager):
def published(self):
return self.filter(status='p')
class Category(models.Model):
title = models.CharField(max_length=100, verbose_name="عنوان دسته بندی")
slug = models.SlugField(max_length=200, unique=True, verbose_name="آدرس")
status = models.BooleanField(
default=True, verbose_name="آیا نمایش داده شود؟")
position = models.IntegerField(verbose_name="پوزیشن")
class Meta:
verbose_name = "دسته بندی"
verbose_name_plural = "دسته بندی ها"
ordering = ['position']
def __str__(self):
return self.title
class Post(models.Model):
STATUS_CHOICES = [
('d', 'پیش نویس'),
('p', 'منتشر شده'),
]
title = models.CharField(max_length=100, verbose_name="عنوان")
slug = models.SlugField(max_length=200, unique=True, verbose_name="آدرس")
category = models.ManyToManyField(
Category, verbose_name="دسته بندی", related_name="postcat")
description = models.TextField(verbose_name="توضیحات")
thumbnail = models.ImageField(
upload_to="imgpost", height_field=None, width_field=None, max_length=None, verbose_name="تصویر")
publish = models.DateTimeField(
default=timezone.now, verbose_name="زمان انتشار")
created = models.DateTimeField(
auto_now_add=True, verbose_name="زمان ایجاد")
updated = models.DateTimeField(
auto_now=True, verbose_name="زمان بروزرسانی")
status = models.CharField(
max_length=1, choices=STATUS_CHOICES, verbose_name="وضعیت")
def __str__(self):
return self.title
class Meta:
verbose_name = "پست"
verbose_name_plural = "پست ها"
objects = PostManager()
#template
{% for posts in categorys.postcat.published %}
<p>
posts.title
</p>
<p>
posts.description
</p>
{%endfor%}
The problem is that despite the filter I have set for not displaying draft posts, that post is not displayed in the category section. If you can help. my project in my github
{% for posts in categorys.postcat.published %}
<p>
{{ posts.title }}
</p>
<p>
{{ posts.description }}
</p>
{%endfor%}
try this!
We have to put this line of code in the model, the post class. It was a back fever.
objects = PostManager()
Here is my models.py py file.
from django.db import models
from django.conf import settings
from django.urls import reverse
class Article(models.Model):
'''Modelling the article section.'''
title = models.CharField(max_length=200)
body = models.TextField()
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
'''Return string representation of the model.'''
return self.title
def get_absolute_url(self):
'''Return the url of this model.'''
return reverse('article_detail', args=[str(self.id)])
class Comment(models.Model):
'''Modelling the comment section.'''
article = models.ForeignKey(
Article,
on_delete = models.CASCADE,
related_name = 'comments'
)
comment = models.CharField(max_length=150)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
def __str__(self):
'''String representation of the model. '''
return self.comment
class Reply(models.Model):
''' Modelling the reply section. '''
comment = models.ForeignKey(
Comment,
on_delete = models.CASCADE,
related_name = 'replys'
)
reply = models.CharField(max_length=100)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
''' String representation of the model. '''
return self.reply
I need to access my Reply table in the Detail View template(Using generic view class DetailView). I have tried so far the following command in the template.
article.comments.replys.all
Its not able to retrive any data from Reply table. Thanks in advance.
article.comments is a manager; you need to iterate over it to get Comment instances. Each one will have .replys.
{% for comment in article.comments.all %}
{% for reply in comment.replys.all %}
...
{% endfor %}
{% endfor %}
I have a django project where I am displaying products in the template. What is the best possible way of displaying the product by category using some sort of template filter. For instance, on the template if I want to display Breads by category Hovis. At the moment all the products in the database will be displayed.
<tr>
<td><h5>{{ product.name }}</h5></td>
<td><p><strong>{{ product.price }}</strong></p></td>
</tr>
Copy of Models.py (as requested):
from django.db import models
from django.core.urlresolvers import reverse
class Category(models.Model):
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True)
class Meta:
ordering = ('name',)
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
# def get_absolute_url(self):
# return reverse('shop:product_list_by_category', args=[self.slug])
class Product(models.Model):
category = models.ForeignKey(Category, related_name='products')
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('-created',)
index_together = (('id', 'slug'),)
def __str__(self):
return self.name
# def get_absolute_url(self):
I would send the already prepared data from the view to the template to avoid additional logic in the front-end. You could do something like this in the view:
products = Product.objects.all()
all_products_by_cat ={}
for product in products:
if all_products_by_cat.get(product.category):
all_products_by_cat[product.category].append(product)
else:
all_products_by_cat[product.category] = [product]
And in the template you would just do:
{% for product in all_products_by_cat['some_category'] %}
<!-- do something with the product-->
{% endfor %}
I have a view which is returning all products, not just filtered ones. Even if I removed the last line products =, the template still renders all database objects.
class ProductListView(ListView):
context_object_name = 'products'
model = models.Product
template_name = "catalogue/catalogue.html"
products = Product.objects.filter(category__name="sundries")
This is my template logic:
{% for product in products %}
<tr>
<td><h5>{{ product.name }}</h5>
<p>Cooked with chicken and mutton cumin spices</p></td>
<td><p><strong>£ {{ product.price }}</strong></p></td>
<td class="options"><i class="icon_plus_alt2"></i></td>
</tr>
{% endfor %}
and Models.py
lass Category(models.Model):
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True)
class Meta:
ordering = ('name',)
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
# def get_absolute_url(self):
# return reverse('shop:product_list_by_category', args=[self.slug])
class Product(models.Model):
category = models.ForeignKey(Category, related_name='products')
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('-created',)
index_together = (('id', 'slug'),)
def __str__(self):
return self.name
# def get_absolute_url(self):
# return reverse('shop:product_detail', args=[self.id, self.slug])
short way
from .models import Product
class ProductListView(ListView):
template_name = "catalogue/catalogue.html"
def get_queryset(self):
category = self.kwargs.get("category")
if category:
queryset = Product.objects.filter(category__iexact=category)
else:
queryset = Product.objects.all()
return queryset
Remember you are working with Generic templates
and of course this is guide and you need make a littles changes in this version of code. (edited)
class ProductListView(ListView):
context_object_name = 'products'
model = models.Product
template_name = "catalogue/catalogue.html"
queryset = Product.objects.all()
def get_category(self):
category_name = self.request.GET.get('category', '')
category = None
if category_name:
try:
category = Category.objects.get(name=category_name)
except Category.DoesNotExist, Category.MultipleObjectsReturned:
pass
return category
def get_queryset(self):
queryset = self.queryset
category = self.get_category()
if category:
return queryset.filter(category=category).all()
else:
return queryset
def get_context_data(self, **kwargs):
kwargs['info_you_want'] = 'info_you_want'
kwargs['category_list'] = Category.objects.all()
return super(ProductListView, self).get_context_data(**kwargs)
html
{% for category in category_list%}
<a href="{% url 'product_list' %}?category={{ category.id }}">
{{ category.name }}
</a>
{% endfor %}
the property you want set is queryset not products, for product with category mains ask url 'www.example.com/products/?category=mains' ,for product with category sundries ask url 'www.example.com/products/?category=sundries'
I'm looking to have a counter of numbers from one to ten using a for loop counter in Django, but I don't see any numbers. I don't really understand what I need to put in {{counter}} and {{value}} when looking at the documentation.
List.html
<p class="number">
{% for key, value in data.items %}
{{counter}}: {{value}}
{% endfor %}
<p>
models.py
from django.db import models
from django.core.urlresolvers import reverse
# Create your models here.
class FullArticleQuerySet(models.QuerySet):
def published(self):
return self.filter(publish=True)
class FullArticle(models.Model):
title = models.CharField(max_length=150)
author = models.CharField(max_length=150)
slug = models.SlugField(max_length=200, unique=True)
pubDate = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
category = models.CharField(max_length=150)
heroImage = models.CharField(max_length=250, blank=True)
relatedImage = models.CharField(max_length=250, blank=True)
body = models.TextField()
publish = models.BooleanField(default=True)
gameRank = models.CharField(max_length=150, blank=True, null=True)
objects = FullArticleQuerySet.as_manager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("FullArticle_detailed", kwargs={"slug": self.slug})
class Meta:
verbose_name = "Blog entry"
verbose_name_plural = "Blog Entries"
ordering = ["-pubDate"]
views.py
from django.views import generic
from . import models
from .models import FullArticle
# Create your views here.
class BlogIndex(generic.ListView):
queryset = models.FullArticle.objects.published()
template_name = "list.html"
randomArticle = FullArticle.objects.order_by('?').first()
class BlogDetail(generic.DetailView):
model = models.FullArticle
template_name = "detailed.html"
use {{ forloop.counter }} instead of just {{ counter }}
Also, you are never defining the dictionary data anywhere. What is this supposed to be? Your queryset?