dynamic url for specific primary key in Django - python

My model has a field call topic, and I want to create a page which can show the specific, and the urls can be dynamic path to different topics rendered by the same html template. How do I suppose to do it?
models.py:
TOPIC = (
(0,"Finance"),
(1,"Toys"),
(2,"Foods"),
(3,"Travel"),
)
class Post(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(unique=True, max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE,related_name='blog_posts')
updated_on = models.DateTimeField(auto_now= True)
created_on = models.DateTimeField(auto_now_add=True)
body = RichTextField(null=True)
status = models.IntegerField(choices=STATUS, default=0)
topic = models.IntegerField(choices=TOPIC, default=0)
cover_img = models.ImageField(upload_to='post_cover', null=True, default='post_cover/coming_soon.jpg')
def __str__(self):
return self.name
def get_img(self):
return f"{'/media/post_cover/'+self.cover_img}"
html
<div class="col-md-6 mt-3 ">
<a href="{% url 'topic_list' %}">
<img src="../media/topic/travel3.jpg" alt=''>
</a>
</div>
views.py
def topic_list(request):
posts = Post.objects.filter(topic=0)
context = {'posts': posts, 'autor_list':autor_list}
return render(request, 'topic_list.html', context)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('topic/', views.topic_list, name='topic_list'),
path('<slug:slug>/', views.post_detail, name='post_detail'),]

To generate a dynamic url in the template use url-reversion function with arguments
{% for post in post_list %}
{{ post.name}}
{% endfor %}
this will reverse post_detail url pattern from your urls.py with post.slug value passed to '<slug:slug>/'
If you need to list posts per topic then fix your url pattern and the view like below:
urlpatterns = [
...
path('topic/<int:pk>/', views.topic_post_list, name='topic-posts-list'),
]
def topic_post_list(request, pk):
posts = Post.objects.filter(topic_id=pk, )
context = {'posts': posts, }
return render(request, 'post_list.html', context)

Related

How to direct from post to category page in Django?

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>

pk argument on Django blog

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)

when i uses post.get_absolute_url in href i got this error. how fix this?

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

Django error : NoReverseMatch at /Post/8 Reverse for 'comments' with arguments '('',)' not found

I am working on my project I faced a problem with "COMMENT":
I add a comment as a section when the user clicks "view" button to see the post from the home page.
Django error :
NoReverseMatch at /Post/8
Reverse for 'comments' with arguments '('',)' not found. 1 pattern(s) tried: ['Post/(?P[0-9]+)$']
views.py file
def viewList(request, id):
item = Post.objects.get(id=id)
context = {
'item': item,
'comment_form': comment(),
'comments': item.get_comments.all(),
}
return render(request, 'auctions/item.html', context)
#login_required
def comments(request, id):
listing = Post.objects.get(id=id)
form = comment(request.PSOT)
newComment = form.save(commit=False)
newComment.user = request.user
newComment.listing = listing
newComment.save()
return HttpResponseRedirect(reverse("listing", {'id': id}))
models.py file
class Post(models.Model):
# data fields
title = models.CharField(max_length=64)
textarea = models.TextField()
# bid
price = models.FloatField(default=0)
currentBid = models.FloatField(blank=True, null=True)
imageurl = models.CharField(max_length=255, null=True, blank=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, default="No Category Yet!", null=True, blank=True)
creator = models.ForeignKey(User, on_delete=models.PROTECT)
watchers = models.ManyToManyField(
User, blank=True, related_name='watched_list')
date = models.DateTimeField(auto_now_add=True)
# for activated the Category
activate = models.BooleanField(default=True)
def __str__(self):
return f"{self.title} | {self.textarea} | {self.date.strftime('%B %d %Y')}"
class Comment(models.Model):
body = models.CharField(max_length=100)
createdDate = models.DateTimeField(default=timezone.now)
# link to the post model
auction = models.ForeignKey(
Post, on_delete=models.CASCADE, related_name="get_comments")
user = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=True)
def __str__(self):
return self.createdDate.strftime('%B %d %Y')
HTML file
<!-- Comments -->
<div class="comments">
<p>Add a comment:</p>
<div class="row">
<div class="col-6">
<form action="{% url 'comments' listing.id %}" method="post">
{% csrf_token %}
<div class="input-group">
{{ comment_form }}
</div>
<input type="submit" value="save" class="btn btn-outline-dark btn-sm m-1"/>
</form>
</div>
{% for comment in comments %}
<div class="col-4">
Comments:
<h4>Name: {{comment.user}}</h4>
<h4>Content: {{comment.body}}</h4>
<h4>Date: {{comment.createdDate}}</h4>
</div>
{% endfor %}
</div>
</div>
url.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("category/", views.category, name="category"),
path("Post", views.createList, name="createList"),
#comment url
path("Post/<str:id>", views.viewList, name="viewList"),
path("Post/<int:id>", views.comments, name="comments"),
]
You passed the Post object as item to the template, hence you should resolve the URL with:
<!-- use item not listing &downarrow; -->
<form action="{% url 'comments' item.id %}" method="post">
…
</form>
Your view to create comments also has some mistakes: you should use request.POST, not request.PSOT:
from django.shortcuts import redirect
#login_required
def comments(request, id):
if request.method == 'POST'
form = comment(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.instance.auction_id = id
form.save()
return redirect('viewList', id=id)
Furthermore your comment form should inherit from ModelForm and not Form:
class comment(forms.ModelForm):
class Meta:
model = Comment
fields = ('content',)
widgets = {
'content': forms.Textarea(attrs={"class": "form-control"})
}
finally your urls.py has two (fully) overlapping patterns, you should use a different URL to add the given comment:
urlpatterns = [
# …
#comment url
path('Post/<int:id>', views.viewList, name='viewList'),
path('Post/<int:id>/add', views.comments, name='comments'),
]
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use CommentForm instead of
comment.

Django cannot create or save comments

I cannot Save comments in django
my post model is
#model.py
class Post(models.Model):
thumbnail = models.ImageField()
slug = models.SlugField(null=True)
title = models.CharField(max_length=200)
description = models.TextField()
content = HTMLField(null=True)
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
timeStamp = models.DateTimeField(auto_now_add=True)
commentCount = models.IntegerField(default=0)
viewCount = models.IntegerField(default=0)
def __str__(self):
return self.title
def absoluteUrl(self):
return reverse('postContent', kwargs={
'slug' : self.slug
})
#property
def getComments(self):
return self.comments.all()
my comment model is
#model.py
class Comment(models.Model):
name = models.CharField(max_length=25)
timeStamp = models.DateTimeField(auto_now_add=True)
comment = models.TextField()
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
def __str__(self):
return self.name
my forms.py is
from .models import Post, Comment
class CommentForm(forms.ModelForm):
name = forms.CharField(widget=forms.TextInput(attrs={
'class': 'form-control',
'id' : 'name',
'placeholder': 'Name'
}))
comment = forms.CharField(widget=forms.Textarea(attrs={
'class' : 'form-control w-100',
'id' : 'comment',
'cols' : '30',
'rows' : 9,
'placeholder' : 'Write Comment'
}))
class Meta:
model = Comment
fields = ('name', 'comment')
my view.py is
from .forms import CommentForm
def post(request, slug):
categoryCount = getCategoryCount()
featured = Post.objects.filter(featured=True)
post = get_object_or_404(Post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.instance.post = post
form.save()
else:
form = CommentForm()
context = {
'post' : post,
'featured': featured,
'categoryCount': categoryCount,
'form' : form
}
return render(request, 'post.html', context)
my post.html is
<div class="comment-form">
<h4>Leave a Reply</h4>
<form class="form-contact comment_form" method="POST" action="." id="commentForm">
{% csrf_token %}
<div class="row">
<div class="col-12">
<div class="form-group">
{{ form }}
</div>
</div>
</div>
<div class="form-group">
<button type="submit" class="button button-contactForm btn_1 boxed-btn">Send Message</button>
</div>
</form>
</div>
my urls.py
from Posts.views import posts, post, search
urlpatterns = [
path('admin/', admin.site.urls),
path('posts/', posts, name='postLists'),
path('posts/<slug>', post, name='postContent'),
path('search/', search, name='search'),
path('tinymce', include('tinymce.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I can save comments in admin section but the main problem is when I click the submit button in html the comment is not saving. I am new to django and I cannont figure out the problem.
Is I miss something else?
You can do something like this
temp = form.save(commit=False)
temp.post = post
temp.save()
Update
as per #Abdul Aziz Barkat mentioned you have to change your URL in urls.py add a trailing slash after posts/<slug> and add one more URL to handle POST request
for eg.
from Posts.views import posts, post, search
urlpatterns = [
path('posts/<slug>/', post, name='postContent'),
path('post_comment/<slug>/', post, name='postComment'),
]
and than inside your form action add this
<form method="POST" action="{% url 'postComment' post.slug %}">
and in your view.py
def post(request, slug):

Categories

Resources