I have tried many ways using filter, since get tried to get a single object but it still does work. When i make a post from my admin section everything works fine but when making the post from my front end using a form it creates the posts then shows me object is not iterable "NOTE: the posts get created perfect well" but i get the iterable error and also slug does not auto populate in the frontend automatically as it does in the backend admin section. Any help would be greatly usefull and make my work faster. let me show some of my code
views.py
#this is for allowing user to create a new post from the frontend
def blogpost(request):
if request.method == "POST":
form = BlogPostForm(request.POST, request.FILES)
if form.is_valid():
form = form.save(commit=False)
form.creator = request.user
form.save()
messages.success(request, f'Hi, Your Post have been sent for review and would be live soon!')
else:
form = BlogPostForm()
context = {
"form": form
}
return render(request, 'blog/AddPost.html', context)
#this is for listing all the blog posts
def BlogList(request):
posts = Blog.objects.filter(status='published').order_by('-created').values()
categoriess = Category.objects.all()
context = {
'posts': posts,
'categories': categoriess,
}
return render(request, 'blog/bloghome.html', context)
# This is view for blog details
def BlogDetail(request, blog_slug):
post = get_object_or_404(Blog, slug=blog_slug)
# post = Blog.objects.filter(slug=blog_slug)
categories = Category.objects.all()
comments = post.comments.filter(active=True)
new_comment = None
if request.method == "POST":
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.name = request.user
new_comment.save()
else:
comment_form = CommentForm()
forms.py
class BlogPostForm(forms.ModelForm):
class Meta:
model = Blog
fields = ['title', 'slug', 'content', 'image', 'category', 'tags']
models.py
class Blog(models.Model):
title = models.CharField(max_length=10000, null=True, blank=True, verbose_name="Title")
content = models.TextField(verbose_name="Post Content")
slug = models.SlugField(unique=True)
image = models.ImageField(upload_to="blog-images/%Y/%m/%d/", verbose_name="Post Thumbnail")
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, verbose_name="Category", null=True)
tags = models.ManyToManyField(Tag, related_name='tags', verbose_name="Tag", null=True)
status = models.CharField(choices=STATUS_CHOICE, default="published", max_length=150, verbose_name='Status')
creator = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="Creator", null=True)
created = models.DateTimeField(auto_now_add=True ,verbose_name="Created", null=True)
def get_absolute_url(self):
return reverse('blog:blog-details', args=[self.slug])
class Meta:
verbose_name = "Blog Post"
verbose_name_plural = "Blog Posts"
def __str__(self):
return self.title
urls.py
urlpatterns = [
path('', views.BlogList, name="home"),
path('post/<slug:blog_slug>', views.BlogDetail, name="blog-details"),
path('post/categories/<slug:category_slug>', views.category, name="category"),
path('post/tags/<slug:tag_slug>', views.tag, name="tags"),
path('post/create/', views.blogpost, name="add-post"),
bloghome.html
<!-- this would list out all the blog post -->
{% for post in posts %}
<div class="col-lg-4 col-md-6 col-sm-12">
<div class="articles_grid_style style-2">
<div class="articles_grid_thumb">
<a href="{{post.get_absolute_url}}"><img src="{{post.image.url}}" class="img-fluid" alt="" style="width: 450px; height: 250px;"></a>
</div>
<div class="articles_grid_caption">
<div class="mpd-date-wraps">
<!-- <span >10</span> -->
<span class="mpd-meta-month">{{post.created|date:"d, M Y"}}</span>
</div>
<div class="blog-grid-cat" style="background: rgb(161, 161, 161); color: white;">{{post.category}}</div>
<a href="{{post.get_absolute_url}}"><h4>{{post.title|truncatechars:70}}</h4></a>
<div class="articles_grid_desc">
<p style="color: black;">{{post.content|truncatechars:80}}</p>
</div>
</div>
<div class="articles_grid_caption-footer">
<div class="articles_grid_author">
<div class="articles_grid_author_img"><img src="{{post.creator.profile.image.url}}" class="img-fluid" alt=""></div>
<a href="">
<h4>{{post.creator.profile.first_name}} {{post.creator.profile.last_name}}</h4>
</a>
</div>
<div class="footer-flex-last">
<a href="{{post.get_absolute_url}}" class="bl-detail-view" style="background:linear-gradient(230deg, rgb(255, 0, 157) 0%, rgb(111, 0, 255) 100%), url(assets/img/tag-light.png) no-repeat; color: white;"><b>READ MORE</b></a>
</div>
</div>
</div>
</div>
{% endfor %}
addpost.html
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form|crispy}}
<div class="form-group">
<button class="btn theme-bg rounded" type="submit">Send Message</button>
</div>
</form>
blogdetails.html
<div class="post-featured-img">
<img class="img-fluid" src="{{ post.image.url }}" alt="">
</div>
<div class="post-top-meta">
<ul class="meta-comment-tag">
<li><a href="#"><span class="icons"><i class="ti-user"></i></span>by {{ post.creator.profile.first_name }} {{ post.creator.profile.last_name }}</a></li>
<li><a href="#"><span class="icons"><i class="ti-comment-alt"></i></span>{{comments.count}} Comments</a></li>
</ul>
</div>
<h2 class="post-title">{{ post.title }}</h2>
<p style="color: black;">{{ post.content }}<p>
CodePudding user response:
It would be helpful to see your template code, but here are a few issues I see.
First, your blogpost
view. When you do a POST request, after you save the form and set the success message, redirect to the BlogDetail
view. The way you have coded it, after saving the form it will again render the blogpost
view, this time with the form containing the request POST data. Look up redirect
here.
Second, in your BlogList
view, you are calling .values()
on your posts
queryset. Without seeing your template code, I cant tell if this is intentional, but make sure you know what values()
returns from a queryset. You might not want to use it.
Third, your BlogDetail
view does not return anything, you need to return a HttpResponse using for example render
like your other views.
And just as a final note, its common convention to name function based views in lower case, with _ as space. CamelCase is reserved for class based views.