I'm working on my blog. I'm trying to list my latest posts in page list_posts.html.I tried but posts are not shown, I don't know why. I don't get any errors or anything, any idea why my posts aren't listed?
This is models.py
from django.db import models
from django.utils import timezone
from ckeditor.fields import RichTextField
from stdimage import StdImageField
STATUS = (
(0,"Publish"),
(1,"Draft"),
)
class Category(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
title = models.CharField(max_length=255, verbose_name="Title")
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
ordering = ['title']
def __str__(self):
return self.title
class Post(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
is_published = models.BooleanField(default=False, verbose_name="Is published?")
published_at = models.DateTimeField(null=True, blank=True, editable=False, verbose_name="Published at")
title = models.CharField(max_length=200, verbose_name="Title")
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey('auth.User', verbose_name="Author", on_delete=models.CASCADE)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE)
body = RichTextField(blank=True, null=True)
image = StdImageField(upload_to='featured_image/%Y/%m/%d/', variations={'standard':(1170,820),'banner':(1170,530),'thumbnail':(500,500)})
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['-created_at']
def publish(self):
self.is_published = True
self.published_at = timezone.now()
self.save()
def __str__(self):
return self.title
This is views.py
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from .models import Category, Post
def post_list(request):
posts = Post.objects.filter(published_at__lte=timezone.now()).order_by('published_at')
latest_posts = Post.objects.filter(published_at__lte=timezone.now()).order_by('published_at')[:5]
context = {'posts': posts, 'latest_posts': latest_posts}
return render(request, 'list_posts.html', context)
def post_detail(request, pk, post):
latest_posts = Post.objects.filter(published_at__lte=timezone.now()).order_by('published_at')[:5]
post = get_object_or_404(Post, pk=pk)
context = {'post': post, 'latest_posts': latest_posts}
return render(request, 'post_detail.html', context)
This is list_posts.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<!-- Main Wrap Start -->
<main class="position-relative">
<div class="post-carausel-1-items mb-50">
{% for post in latest_posts %}
<div class="col">
<div class="slider-single bg-white p-10 border-radius-15">
<div class="img-hover-scale border-radius-10">
<span class="top-right-icon bg-dark"><i class="mdi mdi-flash-on"></i></span>
<a href="{{ post.get_absolute_url }}">
<img class="border-radius-10" src="{{ post.image.standard.url }}" alt="post-slider">
</a>
</div>
<h6 class="post-title pr-5 pl-5 mb-10 mt-15 text-limit-2-row">
{{ post.title }}
</h6>
<div class="entry-meta meta-1 font-x-small color-grey float-left text-uppercase pl-5 pb-15">
<span class="post-by">By {{ post.author }}</span>
<span class="post-on">{{ post.created_at}}</span>
</div>
</div>
</div>
{% endfor %}
</div>
</main>
{% endblock content%}
Everything works except that posts aren't listed. Why I don't get listed posts?
Thanks in advance!
The reason this doesn't work is because the published_at is apparently NULL and is thus never filled in. With the .filter(published_at__lte=timezone.now()), it checks that the published_at is less than or equal to the current timestamp. If it is NULL, it thus is excluded. That means that you will either need to fill in the published_at some way, or filter (and order) with a different field, like created_at. You can thus work with:
from django.db.models.functions import Now
from django.shortcuts import get_object_or_404, render
from .models import Category, Post
def post_list(request):
posts = Post.objects.filter(created_at__lte=Now()).order_by('-created_at')
latest_posts = posts[:5]
context = {'posts': posts, 'latest_posts': latest_posts}
return render(request, 'list_posts.html', context)
def post_detail(request, pk, post):
latest_posts = Post.objects.filter(created_at__lte=Now()).order_by(
'-created_at'
)[:5]
post = get_object_or_404(Post, pk=pk)
context = {'post': post, 'latest_posts': latest_posts}
return render(request, 'post_detail.html', context)
Note: You can work with Now [Django-doc] to work with the database timestamp instead. This can be useful if you want to specify the queryset in a class-based view, since each time the queryset is evaluated, it will then take the (updated) timestamp.
Related
I'm working on my Django blog. I have a trouble to redirect from post to category, when you open post you can click to category and when you click on category I want you to redirect you to category and show posts only from that category.
This part of my html code for post_detail.html
<div class="entry-meta meta-0 font-small mb-30"><span class="post-cat bg-success color-white">{{ post.category}}</span></div>
<h1 class="post-title mb-30">
{{ post.post_title }}
</h1>
This is models.py only class category
class Category(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
category_name = models.CharField(max_length=255, verbose_name="Category name")
slug = models.SlugField(max_length=200, unique=True)
def get_absolute_url(self):
return reverse('category_detail', args=[self.slug])
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
ordering = ['category_name']
def __str__(self):
return self.category_name
in post_detail is defined like this (short view)
class Post(models.Model):
...
post_title = models.CharField(max_length=200, verbose_name="Title")
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE)
...
def __str__(self):
return self.post_title
This is views.py
def post_detail(request, slug):
latest_posts = Post.objects.filter(created_at__lte=timezone.now()).order_by('created_at')[:9]
post = get_object_or_404(Post, slug=slug)
context = {'post': post, 'latest_posts': latest_posts}
return render(request, 'post_detail.html', context)
def category_detail(request, pk):
category = get_object_or_404(Category, pk=pk)
return render(request, 'category_detail.html', {'category': category})
This is urls.py
from . import views
from django.urls import path
urlpatterns = [
path('', views.home, name='home'),
path('<slug:slug>/', views.post_detail, name='post_detail'),
path('<slug:slug>/', views.category_detail, name='category_detail'),
]
Any idea why I'm not redirected to category_detail page?
Thanks in advance!
first of all edit your Post model and add related_name option to category field.
class Post(models.Model):
...
post_title = models.CharField(max_length=200, verbose_name="Title")
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE, related_name='posts')
...
def __str__(self):
return self.post_title
now in your category detail template you can access Posts related to that category:
in category_detail.html:
{% for post in category.posts.all %}
{{ post.post_title }}
{% endfor %}
and you need to edit your post_detail.html:
change {{ category.get_absolute_url }} to {{ post.category.get_absolute_url }}
<div class="entry-meta meta-0 font-small mb-30"><span class="post-cat bg-success color-white">{{ post.category}}</span></div>
<h1 class="post-title mb-30">
{{ post.post_title }}
</h1>
I'm working on a blog and I was following instructions but now I don't understand why I have problem with pk.
This is my views.py
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from .models import Category, Post
def post_list(request):
posts = Post.objects.filter(created_at__lte=timezone.now()).order_by('created_at')
latest_posts = Post.objects.filter(created_at__lte=timezone.now()).order_by('created_at')[:9]
context = {'posts': posts, 'latest_posts': latest_posts}
return render(request, 'home.html', context)
def post_detail(request, post, pk):
latest_posts = Post.objects.filter(created_at__lte=timezone.now()).order_by('created_at')[:9]
post = get_object_or_404(Post, pk=pk)
context = {'post': post, 'latest_posts': latest_posts}
return render(request, 'post_detail.html', context)
This is blog/urls.py
urlpatterns = [
path('', views.post_list, name='home'),
path('<slug:post>/', views.post_detail, name='post_detail'),
]
This is models.py
class Post(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
is_published = models.BooleanField(default=False, verbose_name="Is published?")
published_at = models.DateTimeField(null=True, blank=True, editable=False, verbose_name="Published at")
title = models.CharField(max_length=200, verbose_name="Title")
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey('auth.User', verbose_name="Author", on_delete=models.CASCADE)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE)
body = RichTextField(blank=True, null=True)
image = StdImageField(upload_to='featured_image/%Y/%m/%d/', variations={'standard':(1170,820),'banner':(1170,530),'thumbnail':(500,500)})
status = models.IntegerField(choices=STATUS, default=0)
def get_absolute_url(self):
return reverse('post_detail', args=[self.slug])
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['-created_at']
def publish(self):
self.is_published = True
self.published_at = timezone.now()
self.save()
def __str__(self):
return self.title
Also, I'm adding a list of post, it might be connected with get_absolute_url
{% extends "base.html" %}
{% load static %}
{% block content %}
<!-- Main Wrap Start -->
<main class="position-relative">
<div class="post-carausel-1-items mb-50">
{% for post in latest_posts %}
<div class="col">
<div class="slider-single bg-white p-10 border-radius-15">
<div class="img-hover-scale border-radius-10">
<!--<span class="top-right-icon bg-dark"><i class="mdi mdi-flash-on"></i></span>-->
<a href="{{ post.get_absolute_url }}">
<img class="border-radius-10" src="{{ post.image.standard.url }}" alt="post-slider">
</a>
</div>
<h6 class="post-title pr-5 pl-5 mb-10 mt-15 text-limit-2-row">
{{ post.title }}
</h6>
<div class="entry-meta meta-1 font-x-small color-grey float-left text-uppercase pl-5 pb-15">
<span class="post-by">By {{ post.author }}</span>
<span class="post-on">{{ post.created_at}}</span>
</div>
</div>
</div>
{% endfor %}
</div>
</main>
{% endblock content%}
I have an error...
post_detail() missing 1 required positional argument: 'pk'
Everything was working until I was started working on post detail. Any ideas why this is happening?
You seem to be confused with what the primary key for your model is. The primary key is the auto-generated id (pk) but according to your urls.py you want to use slug for fetching records.
First, change your path to:
path('<slug:slug>/', views.post_detail, name='post_detail'),
then your view signature to:
def post_detail(request, slug):
and finally, fetch your record using:
post = get_object_or_404(Post, slug=slug)
I want to put a filter on a page which shows videos selecting an album shows up on album page not all the videos but my current filter is showing all the published videos. I couldn't find a way to put a filter based on slug that if an album's slug is matching with the current url then shows the video selecting that album. For example:- Videos created by Gaurav should only visible on Gaurav’s album not anyone else. I am all confused help me.
models.py
from django.db import models
from django.urls import reverse
STATUS = (
(1, "Publish"),
(0, "Draft")
)
class WatchCategory(models.Model):
title = models.CharField(max_length=20)
slug = models.SlugField(max_length=2000, unique=True)
def __str__(self):
return self.title
class Genre(models.Model):
title = models.CharField(max_length=20)
slug = models.SlugField(max_length=2000, unique=True)
def __str__(self):
return self.title
class Album(models.Model):
title = models.CharField(max_length=2000)
slug = models.SlugField(max_length=2000, unique=True)
image = models.CharField(max_length=2000, blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('Watch:album', kwargs={
'slug': self.slug
})
class Video(models.Model):
title = models.CharField(max_length=2000)
slug = models.SlugField(max_length=2000, unique=True)
thumbnail = models.CharField(max_length=2000, unique=True)
updated_on = models.DateTimeField(auto_now=True)
file = models.CharField(max_length=2000)
time = models.CharField(max_length=2000, blank=True)
about = models.TextField(blank=True)
category = models.ManyToManyField(WatchCategory)
album = models.ManyToManyField(Album)
genre = models.ManyToManyField(Genre)
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=1)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('Watch:video', kwargs={
'slug': self.slug
})
views.py
class Album(ListView):
queryset = Video.objects.filter(status=1).order_by('-created_on')
template_name = 'Watch/album.html'
paginate_by = 6
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = 'Explore & Watch your favourite'
return context
album.html
{% extends "Watch/layout.html" %}
{% load static %}
{% block content %}
<div class="video-block section-padding">
<div class="row">
{% for video in video_list %}
<div class="col-xl-3 col-sm-6 mb-3">
<div class="video-card">
<div class="video-card-image">
<a class="play-icon" href="{% url 'Watch:video' video.slug %}"><i class="fas fa-duotone fa-circle-play"></i></a>
<img class="img-fluid" src="{{ video.thumbnail }}" alt="">
<div class="time">{{ video.time }}</div>
</div>
<div class="video-card-body">
<div class="video-title">
{{ video.title }}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
AttributeError at /blog/
Manager isn't accessible via Post instances
Error during template rendering
In template C:\Users\Mahdyar Eatemad\OneDrive\Projects\Gallery\templates\blog\post\list.html, error at line 33
Manager isn't accessible via Post instances
error
i used get_absolute_url to create slug for blog posts
This is my models
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from django.urls import reverse
# Create your models here.
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'چرک نویس'),
('published', 'منتشر شده'),
)
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, unique_for_date='publish', allow_unicode=True)
body = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
bolded_text = models.TextField(blank=True)
picture = models.ImageField(upload_to='photos', blank=True)
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def get_absolute_url(self):
return reverse('blog:post_detail', args=[self.published.year, self.published.month, self.published.day, self.slug])
def __str__(self):
return self.title
my views
from django.shortcuts import render, get_object_or_404
from .models import Post
# Create your views here.
def post_list(request):
posts = Post.published.all()
return render(request, 'blog/post/list.html', {'posts': posts})
def post_detail(request, year, month, day, slug):
post = get_object_or_404(Post, slug=slug, status='published', published__year=year, published__month=month, published__day=day)
return render(request, 'blog/post/list.html', {'post': post})
my url
from django.urls import path, register_converter
from django.urls.converters import SlugConverter
from . import views
app_name = 'blog'
class PersianSlugConvertor(SlugConverter):
regex = '[-a-zA-Z0-9_ضصثقفغعهخحجچگکمنتالبیسشظطزژرذدپوءآ]+'
register_converter(PersianSlugConvertor, 'persian_slug')
urlpatterns = [
path('', views.post_list, name='post_list'),
path('<int:year>/<int:month>/<int:day>/<persian_slug:slug>', views.post_detail, name='post_detail'),
]
template
{% for post in posts %}
<article class="post">
<div class="post_header">
<h3 class="post_title">{{ post.title }}</h3>
<div class="post_sub"><i class="fa-time"></i>منتشر شده در {{ post.publish }} توسط {{ post.author }}<i class="fa-comments-alt"></i> 6 نظر </div>
</div>
<div class="post_content">
<figure><img alt="عکس پست" src="{{ post.picture }}"></figure>
<p>{{ post.body|truncatewords:30|linebreaks }}</p>
بیشتر بخوانید </div>
</article>
{% endfor %}
you write
reverse('blog:post_detail', args=[self.published.year,
self.published.month, self.published.day, self.slug])
where you are referencing published which is a manager, instead you want to refer to publish which is your date time field
I am trying to add comment to an Ad posted by a user. When I press the comment button, it is showing the error.
Here's my models.py
from django.db import models
from django.core.validators import MinLengthValidator
from django.contrib.auth.models import User
from django.conf import settings
class Ad(models.Model):
title = models.CharField(
max_length=200,
validators=[MinLengthValidator(2, "Title must be greater than 2 characters")]
)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
text = models.TextField()
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#picture
picture = models.BinaryField(null=True, blank=True, editable=True)
content_type = models.CharField(max_length=256, null=True, help_text='The MIMEType of the file')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
comments = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Comment', related_name='comments_owned')
#show up in the admin list
def __str__(self):
return self.title
class Comment(models.Model) :
text = models.TextField(
validators=[MinLengthValidator(3, "Comment must be greater than 3 characters")]
)
ad = models.ForeignKey(Ad, on_delete=models.CASCADE)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# Shows up in the admin list
def __str__(self):
if len(self.text) < 15 :
return self.text
return self.text[:11] + ' ...'
Here's my forms.py
# commentForm
from django import forms
from ads.models import Ad, Comment
from django.core.files.uploadedfile import InMemoryUploadedFile
from ads.humanize import naturalsize
from django.core import validators
from django.core.exceptions import ValidationError
...
class CommentForm(forms.Form):
comment = forms.CharField(required=True, max_length=500, min_length=3, strip=True)
class Meta:
model = Comment
fields = ['text']
Here's my views.py
from ads.models import Ad, Comment
from ads.owner import OwnerListView, OwnerDetailView, OwnerCreateView, OwnerUpdateView, OwnerDeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.views import View
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy, reverse
from django.http import HttpResponse
from ads.forms import CreateForm, CommentForm
class AdDetailView(OwnerDetailView):
model = Ad
def get(self, request, pk):
a = Ad.objects.get(id=pk)
comments = Comment.objects.filter(ad=a).order_by('-updated_at')
comment_form = CommentForm()
context = {'ad': a, 'comments':comments, 'comment_form':comment_form}
return render(request, 'ads/ad_detail.html', context)
....
class CommentCreateView(LoginRequiredMixin, View):
def post(self, request, pk):
ad = get_object_or_404(Ad, id=pk)
comment = Comment(text=request.POST['comment'], owner=request, ad=ad)
comment.save()
return redirect(reverse('ads:ad_detail', args=[pk]))
class CommentDeleteView(OwnerDeleteView):
model = Comment
def get_success_url(self):
ad = self.object.ad
return reverse('ads:ad_detail', args=[ad.id])
And finally my templates ad_detail.html
{% if user.is_authenticated %}
<br clear="all"/>
<p>
{% load crispy_forms_tags %}
<form method="post" action="{% url 'ads:ad_comment_create' ad.id %}">
{% csrf_token %}
{{ comment_form|crispy }}
<input type="submit" value="Submit">
<input type="submit" value="All Ads" onclick="window.location.href='{% url 'ads:all' %}'; return false;">
</form>
</p>
{% endif %}
{% for comment in comments %}
<p> {{ comment.text }}
({{ comment.updated_at|naturaltime }})
{% if user == comment.owner %}
<i class="fa fa-trash"></i>
{% endif %}
</p>
{% endfor %}
After clicking on the submit button, it's supposed to be taking to ads:all but instead throwing an error.
In case you also want to check urls.py
urlpatterns = [
path('', views.AdListView.as_view()),
path('ads', views.AdListView.as_view(), name='all'),
...
#comments
path('ad/<int:pk>/comment', views.CommentCreateView.as_view(), name='ad_comment_create'),
path('comment/<int:pk>/delete', views.CommentDeleteView.as_view(success_url=reverse_lazy('ads')), name='ad_comment_delete'),
]
You should be using ModelForm instead of Form here.
class CommentForm(forms.ModelForm):
comment = forms.CharField(required=True, max_length=500, min_length=3, strip=True)
class Meta:
model = Comment
fields = ['text']
And change your view
class CommentCreateView(LoginRequiredMixin, View):
def post(self, request, pk):
form = CommentForm(request.POST)
ad = get_object_or_404(Ad, id=pk)
comment = form.save(commit=False)
comment.ad = ad
comment.owner = request.user
comment.save()
return redirect('ads:ad_detail', ad.pk)
In you CommentCreateView, your owner is recieving request that was the reason you were shown that error. So:
comment = Comment(text=request.POST['comment'], owner=request.user, ad=ad)