Django - How to create a slug url that works? - python

I'm a newbie and I've been battling with an error while trying to display the detail page of a post. I've checked other answers relating to this question but the solutions still don't work for me.
This is the error I'm getting:
Reverse for 'blog_post' with no arguments not found. 1 pattern(s) tried: ['blog\\/post/(?P<slug>[-\\w]+)/$']
This is my model:
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique_for_date='publish')
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
body = models.TextField()
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')
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post', args=[str(self.slug)])
View functions:
class BlogHomePageView(ListView):
model = Post
template_name = 'blog/index.html'
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post.html'
slug_url_kwarg = 'slug'
query_pk_and_slug = True
Urlpatterns:
path('', BlogHomePageView.as_view(), name='blog_home'),
re_path(r'post/(?P<slug>[-\w]+)/$', PostDetailView.as_view(), name='blog_post'),
base.html
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand" href="index.html">Toluwalemi</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse"
data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false"
aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'blog_home' %}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'blog_about' %}">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'blog_post' %}">Sample Post</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'blog_contact' %}">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
detail page:
{% extends 'blog/base.html' %}
{% block title %}Post{% endblock %}
<!-- Page Header -->
{% block page_header %}
<div class="post-heading">
<h1>{{ post.title }}</h1>
<h2 class="subheading">Problems look mighty small from 150 miles up</h2>
<span class="meta">Posted by
{{ post.author }}
on {{ post.publish }}</span>
</div>
{% endblock %}
<!-- Post Content -->
<article>
{% block content %}
<p>{{ post.body }}</p>
list page:
{% extends 'blog/base.html' %}
{% block title %}Home{% endblock %}
<!-- Page Header -->
{% block page_header %}
<div class="site-heading">
<h1>Toluwalemi's Blog</h1>
<span class="subheading">Official Blog</span>
</div>
{% endblock %}
<!-- Main Content -->
{% block content %}
{% for post in object_list %}
<div class="post-preview">
<a href="{{ post.get_absolute_url }}">
<h2 class="post-title">
{{ post.title }}
</h2>

If you look at your URL definition, you can see that it expects an argument slug:
re_path(r'post/(?P<slug>[-\w]+)/$', PostDetailView.as_view(), name='blog_post'),
which, by the way, could also be expressed as as of Django 2.0:
path('post/<slug:slug>/', PostDetailView.as_view(), name='blog_post'),
Now, the error message from the image shows clearly that you are calling the URL template tag without said argument, it only has
href="{% url 'blog_post' %}"
and no slug argument is present.
You need to add the slug argument.
You have not even shown us the right template in your question where the line appears that is shown in the error message, so I cannot help further than this.

So guys, I finally figured it out. My slug url is now working perfectly.
The error was actually coming from my list page. The url to the detail view wasn't written well. I didn't include a namespace. So instead of <a href="{{ post.get_absolute_url }}"> it becomes <a href="{% url 'blog:blog_post' post.slug %}">
I also deleted redundant lines of codes in my models and my views page.
Here is what it looks like now.
models.py:
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, default="")
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
body = models.TextField()
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')
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
views.py
class BlogHomePageView(ListView):
model = Post
template_name = 'blog/index.html'
context_object_name = 'posts'
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post.html'
context_object_name = 'post'
blog/urls.py:
urlpatterns = [
path('', BlogHomePageView.as_view(), name='blog_home'),
path('post/<slug:slug>/', PostDetailView.as_view(), name='blog_post'),
]
list page(index.html):
{% extends 'blog/base.html' %}
{% block title %}Home{% endblock %}
<!-- Page Header -->
{% block page_header %}
<div class="site-heading">
<h1>Toluwalemi's Blog</h1>
<span class="subheading">Official Blog</span>
</div>
{% endblock %}
<!-- Main Content -->
{% block content %}
{% for post in posts %}
<div class="post-preview">
<a href="{% url 'blog:blog_post' post.slug %}">
<h2 class="post-title">
{{ post.title }}
</h2>

Related

how to use class based views for a single page blog with pagination in django

this is the error messag am getting in a picture someone should please help me solve this problem i have been on it for the past 3days,
i have a single blog which is handled by multiple author or admin,so i decided to use class based views and when i create a new post gives an error saying i need blog_detail.html,since i dont have detail blog so i created a Detailview then adding my template_name = 'mymainblogpage.html' so once i create new post it will get posted but wont show the post but will only show the pagination,besides i cant search by post id for example http://127.0.0.1:8000/pages/blog/49/ i just get nothing here is my code.
views.py
def blog(request):
blog_post = Blog.objects.all()
ordering = ['-timestamp']
paginator = Paginator(blog_post, 2)
page_request_var = 'page'
page = request.GET.get(page_request_var)
try:
paginated_queryset = paginator.page(page)
except PageNotAnInteger:
paginated_queryset = paginator.page(2)
except EmptyPage:
paginated_queryset = paginator.page(paginator.num_pages)
context = {
'queryset': paginated_queryset,
'page_request_var': page_request_var
}
return render(request, 'pages/blog.html', context)
class BlogDetailView(DetailView):
model = Blog
template_name = 'pages/blog.html'
context_object_name = 'blog'
urls.py
path('blog/', BlogDetailView.as_view(), name='blog'),
path('blog/<int:pk>/', BlogDetailView.as_view(), name='blog-detail'),
models.py
def get_absolute_url(self):
return reverse('blog-detail', kwargs={'pk': self.pk})
blog.html
<br><p></p>
<section class="ftco-section bg-light" id="blog-section">
<div class="container">
<div class="row justify-content-center mb-5 pb-5">
<div class="col-md-10 heading-section text-center ftco-animate">
<h2 class="mb-4">Gets Every Single Updates Here</h2>
<p>Far far away, behind the word mountains, far from the countries Vokalia and Consonantia</p>
</div>
</div>
<div class="container">
<div class="row justify-content-center mb-5 pb-5">
<div class="col-lg-8 ftco-animate">
{% for blog in queryset %}
<h2 class="text-center">{{ blog.title }}</h2>
<div class="meta mb-3 text-center">
<div><h6><span><a href = "">written By {{ blog.user }}</span><small class="date"><i class="icon-clock"></i> {{ blog.timestamp|timesince }} ago</small><a/></h6>
</div>
</div>
<div><small class="icon-eye text-danger">{{ blog.view_count }}</small></div>
<div class="meta mb-3 text-center">
<h5>{% for cat in blog.categories.all %}<span class="btn btn-dark">{{ cat }}</span> {% endfor %}</h5>
</div>
<p class="text-center">{{ blog.overview }}</p>
{% endfor %}
<nav aria-label="pagination">
<ul class="pagination pagination-circle pg-blue">
{% if queryset.has_previous %}
<li class="page-item">Previous</li>
{% endif %}
<li class="page-item active">{{ queryset.number }}</li>
</a>
</li>
{% if queryset.has_next %}
<li class="page-item">Next</li>
{% endif %}
</ul>
</nav>
{% if is_paginated %}
<nav aria-label="pagination">
<ul class="pagination pagination-circle pg-blue">
{% if queryset.has_previous %}
<li class="page-item">Previous</li>
{% endif %}
<li class="page-item active">{{ queryset.number }}</li>
</a>
</li>
{% if queryset.has_next %}
<li class="page-item">Next</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
</div>
</div>
</section>
You pagination isn't showing because you are passing context variable 'page_request_var': page_request_var instead of 'page_request_var': page
so change it because page_request_var is just a string 'page'.
If you need to use class-based list view then
from django.views.generic import ListView
class PostListView(ListView):
queryset = Post.published.all()
context_object_name = 'posts' # by default class list view uses object_list.
paginate_by = 2 # number of objects/posts per page
template_name = 'pages/blog.html' # by default uses <appname>/<modelname>_<view_type>.html
also, I would recommend using different templates for list and detail views because you are just searching the same template using so I think that may be a problem.

django bootstrap navbar dropdown elements not coming on other url while using same base.html

I am new to django and creating one app. I have create two mode on is master and other is details.
While using a bootstrap nav bar drop down on a single base.html i am able to get master records in drop down while i switch to different page when clicked any drop down element i didn't get drop down element. I am extending base.html in both the master as well as detail page. Please help with any option
dropdown working
http://127.0.0.1:8000/environment/
dropdown not working
http://127.0.0.1:8000/environment/env_name
base.html
<!-- menu buttons -->
<div class="collapse navbar-collapse" id="topNavBar">
<ul class="nav navbar-nav">
<li class="active">
<li class="nav-item dropdown" >
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Environment
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
{% for envmaster in all_envmaster %}
<a class="dropdown-item" href="{% url 'environment:detail' envmaster.env_name %}">{{ envmaster.env_name }}</a>
<div class="dropdown-divider"></div>
{% endfor %}
</div>
<!--<a href="{% url 'environment:index' %}">
<span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Environment
</a>-->
</li>
</li>
<li class="">
<a href="#">
<span class="glyphicon glyphicon-file" aria-hidden="true"></span> Details
</a>
</li>
</ul>
detail.html
<!-- Loads the path to your static files -->
{% extends 'environment/base.html' %}
{% block title %}Environment Details{% endblock %}
{% block body %}
<!--<img src="{{ envmaster.env_name }}" style="width: 250px;"><br>-->
<h3>{{ envmaster.env_name }}</h3>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
{% csrf_token %}
{% for envdetail in envmaster.envdetail_set.all %}
<li>{{ envdetail.env_component }} - {{ envdetail.component_class }} - {{ envdetail.value_1 }}</li><br>
{% endfor %}
{% endblock %}
index.html
<!-- Loads the path to your static files -->
{% extends 'environment/base.html' %}
{% block title %}Environment Details{% endblock %}
{% block body %}
{% if all_envmaster %}
<h3>Here are all Environment:</h3>
<ul>
{% for envmaster in all_envmaster %}
<li>{{ envmaster.env_name }}</li>
{% endfor %}
</ul>
{% else %}
<h3>You don't have any Environment</h3>
{% endif %}
{% endblock %}
models.py
from django.db import models
from django.urls import reverse
class Envmaster(models.Model):
env_name = models.CharField(primary_key=True, max_length=256)
env_type = models.CharField(max_length=256, blank=True, null=True)
env_owner = models.CharField(max_length=256, blank=True, null=True)
cur_release = models.CharField(max_length=256, blank=True, null=True)
class Meta:
db_table = 'ENVMASTER'
def get_absolute_url(self):
return reverse('environment:detail', kwargs={'pk': self.pk})
def __str__(self):
return self.env_name
class Envdetail(models.Model):
env_name = models.ForeignKey(Envmaster,on_delete=models.CASCADE)
env_component = models.CharField(max_length=256, blank=True, null=True)
component_class = models.CharField(max_length=256, blank=True, null=True)
value_1 = models.CharField(max_length=256, blank=True, null=True)
value_2 = models.CharField(max_length=256, blank=True, null=True)
value_3 = models.CharField(max_length=256, blank=True, null=True)
additional_info = models.CharField(max_length=256, blank=True, null=True)
class Meta:
db_table = 'ENVDETAIL'
def __str__(self):
return self.env_component
views.py
from django.views import generic
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.shortcuts import render, get_object_or_404
from .models import Envmaster
class IndexView(generic.ListView):
template_name = 'environment/index.html'
context_object_name = 'all_envmaster'
def get_queryset(self):
return Envmaster.objects.all()
class DetailView(generic.DetailView):
model = Envmaster
template_name = 'environment/detail.html'
url.py
urlpatterns = [
re_path(r'^$', views.IndexView.as_view(), name="index"),
#/environment/env_name/
re_path(r'^(?P<pk>[\w\-]+)/$', views.DetailView.as_view(), name='detail'),
You need to create a templates folder inside src folder you created and add create base.html inside that folder.
Than add in in you setting.py inside [Templates] add the location of the templates folder like this
'DIRS': [os.path.join(BASE_DIR, 'templates')],
and than just extend you html file
{% extends 'base.html' %}
While going through different posts and trying I have created a context file at app level so that once the class object is initialized it should retain the values within the navigation bar
from .models import Envmaster
def show_env_menu(context):
env_menu = Envmaster.onjects.all()
return {'env_menu': env_menu}

Not being able to display comments in template

I'm making a Post and Comment model by taking reference from internet. i created and Post and Comment model and it looks ok in django admin panel. i can add post and also a comment to any particular post. but getting trouble when I'm trying to display the comment under the post in templates(under post detail views). PLEASE HELP
models.py
class Post(models.Model):
author = models.ForeignKey(User,on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = RichTextField()
tags = models.CharField(max_length=50,blank=True,null=True)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail',kwargs={'pk':self.pk})
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE)
author = models.ForeignKey(User,max_length=50,on_delete=models.CASCADE)
text = models.TextField()
create_date = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse('discuss')
views.py
class PostDetailView(DetailView):
model = Post
def add_comment_to_post(request,pk):
return get_object_or_404(Post,pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post= post
comment.save()
return redirect('post-detail',pk=post.pk)
else:
form = CommentForm()
return render(request, 'discuss/comment_form.html',{'form':form})
def comment_remove(request,pk):
comment = get_object_or_404(Comment,pk=pk)
post_pk = comment.post.pk
comment.delete()
return redirect('post-detail', pk=post_pk)
post_detail.html
{% extends 'index.html' %}
{% block content %}
<article class="media content-section">
<div class="medaia-body">
<img class="rounded-circle article-img" src="{{ object.author.profile.image.url }}" alt="image not found">
<div class="article-metedata">
<a class="mr-2" href="{% url 'user-posts' object.author.username %}">{{object.author}}</a>
<small class="text-muted">{{ object.date_posted|date:"F d, Y"}}</small>
</div>
<h2 class="article-title">{{ object.title }}</h2>
<img class="query-img" src="{{ object.image.url }}" alt="image not found">
<p class="article-content">{{ object.content|safe }}</p>
</div>
</article>
{% if object.author == user %}
<div class="post-update-delete">
<button class="btn btn-outline-primary">Edit Post</button>
<button class="btn btn-outline-primary">Delete Post</button>
</div>
{% endif %}
<hr>
<a class="btn btn-primary btn-comment" href="{% url 'add_comment_to_post' pk=post.pk %}">Add Comment</a>
<!-- ############################### ABOVE CODE IS WORKING ############################# -->
<!-- ########################## GETTING PROBLEM IN BELLOW CODE ######################### -->
{% for comment in object.comments.all %}
{% if user.is_authenticated %}
{{ comment.create_date }}
{{ comment.text|safe|linebreaks }}
{{ comment.author }}
{% endif %}
{% empty %}
<p>No Comment</p>
{% endfor %}
{% endblock %}
in post_deatil.html i also tried {% for comment in post.comments.all %} but it is also not working
Since you did not specify a related_name=… parameter [Django-doc], the related_name is by default comment_set, so you iterate over the comments with:
{% for comment in object.comment_set.all %}
…
{% endfor %}
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

How to limit the number of items displayed in Django app

I have this Django model in my newspaper app:
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
It currently displays all articles but I want to limit what is displayed to the 3 most recent articles. How is that done?
This is my view:
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = 'article_list.html'
login_url = 'login'
This is the html template:
{% extends 'base.html' %}
{% block title %}Articles{% endblock title %}
{% block content %}
{% for article in object_list %}
<div class="card">
<div class="card-header">
<span class="font-weight-bold">{{ article.title }}</span> ·
<span class="text-muted">by {{ article.author }} | {{ article.date }}</span>
</div>
<div class="card-body">
<p>{{ article.body }}</p>
Edit
Delete
</div>
<div class="card-footer">
{% for comment in article.comments.all %}
<p>
<span class="font-weight-bold">{{ comment.author }} ·</span>
{{ comment }}
</p>
{% endfor %}
</div>
</div>
<br />
{% endfor %}
{% endblock content %}
In your (assumed) ListView you should define the queryset, something like
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = 'article_list.html'
login_url = 'login'
queryset = Article.objects.order_by('-date')[:3]
More on this here.

Django Foreign Key class not showing

The goal is to have a dashboard show a list of users in your area. The list of users works and it shows the Username. The only issue is I can't get the users images (ideally just have 1st image) to show. There are no error messages currently. Just nothing appearing.
models.py
class Images(models.Model):
image = models.ImageField(upload_to='profile_image', null=True, default='profile_image/none/no-img.png')
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True, null=True)
birth_date = models.DateField(null=True, blank=True)
...
views.py
class DashboardView(TemplateView):
template_name = 've/cp/dashboard.html'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(DashboardView, self).dispatch(*args, **kwargs)
def get(self, request, pk=None):
users = User.objects.exclude(id=request.user.id)
try:
favorite = Favorite.objects.get(current_user=request.user)
favorites = favorite.users.all()
except Favorite.DoesNotExist:
favorites = None
args = {
# 'users': users, 'favorites':favorites, 'images': images,
}
return render(request, self.template_name, args)
dashboard.html
<div class="col-12">
<h2>People near you</h2>
{% for user in users %}
<a href="{% url 've:view_profile_with_pk' pk=user.pk %}">
<!--THIS WORKS-->
<h4>{{ user.username }}</h4>
<p>{{ user.profile.bio }}</p>
<!--But not this... why..-->
<p>{{ user.images.image.url }}</p>
'''
Or this.. However it does work on view_profile page where
there is a pk. Seem like it's not finding images for users,
as this results in a "No images message on localhost
'''
{% if images %}
{% for img in images %}
<a href="{{ user.img.image.url }}" target="_blank">
<img src="{{ user.img.image.url }}" class="" style="max-width: 300px">
</a>
{% endfor %}
{% else %}
<p>No images</p>
{% endif %}
</a>
<!-- Favorites works great -->
{% if not user in favorites %}
<a href="{% url 've:change_favorites' operation='add' pk=user.pk %}">
<button type="button" class="btn btn-success">Add Favorite</button>
</a>
{% endif %}
{% endfor %}
</div>
You can get user's images direcly from user object using images_set attribute.
In your case you can do something like this:
{% for user in users %}
{% with first_image=user.images_set.first %}
{% if first_image %}
<a href="{{ first_image.image.url }}" target="_blank">
<img src="{{ first_image.image.url }}" class="" style="max-width: 300px">
{% endif %}
{% endwith %}
{% endfor %}

Categories

Resources