Blog matching query does not exist - python

I am using slug to to show my blog details page.
here is models.py
class Blog(models.Model):
author=models.ForeignKey(User,on_delete=models.CASCADE,related_name='post_author')
blog_title=models.CharField(max_length=264,verbose_name='Put a Title')
slug= models.SlugField(max_length=264,unique=True)
blog_content=models.TextField(verbose_name='what is on your mind?')
blog_image=models.ImageField(upload_to='blog_images',verbose_name='Image')
publish_date=models.DateTimeField(auto_now_add=True)
update_date=models.DateTimeField(auto_now=True)
class Meta:
ordering = ('-publish_date',)
def __str__(self):
return self.blog_title+' From :'+str(self.author)
blog list views.py
def Creating_blog(request):
form=BlogForm()
if User.is_authenticated:
if request.method=='POST':
form=BlogForm(request.POST,request.FILES)
blog_obj=form.save(commit=False)
blog_obj.author=request.user
title=blog_obj.blog_title
blog_obj.slug = title.replace(' ','-') + '-'+ str(uuid.uuid4())
blog_obj.save()
return redirect('bloglist')
return render(request,'blogs/createblog.html',{'form':form})
blog details views.py
def blog_details(request, slug):
if User.is_authenticated:
blog= Blog.objects.get(slug=slug)
already_liked=Likes.objects.filter(blog=blog,user=request.user)
if already_liked:
like=True
else:
like=False
comments=Comment.objects.filter(blog=blog)
commet_form=CommentForm()
if request.method=='POST':
commet_form=CommentForm(request.POST)
if commet_form.is_valid():
comment=commet_form.save(commit=False)
comment.user=request.user
comment.blog=blog
comment.save()
return HttpResponseRedirect(reverse('blog_details',kwargs={'slug':slug}))
return render(request,'blogs/blogdetails.html',context={'blog':blog,'comment_form':commet_form,'comments':comments,'like':like})
else:
HttpResponseRedirect(reverse('login'))
urls.py
from django.urls import path
from .import views
urlpatterns = [
path('write/',views.Creating_blog,name='creatingblogs'),
path('bloglist/',views.BlogList.as_view(),name='bloglist'),
path('details/<slug:slug>/',views.blog_details,name="blog_details")
]
blog_list page html anchor tag code
<div class="col-sm-8">
<p>{{blog.blog_content|capfirst|truncatewords:100}}Read More</p>
</div>
I can see the blog list page but when it try to see blog details it shows me this error
DoesNotExist at /details/big-time-space-rarity-9a3d63b4-634a-11ec-9db9-9c7bef6a0e62/
Blog matching query does not exist.
I have tried adding some new blog but it shows me the same. please help me out this and kindly ask me if any description needed. Thanks in advance.

The error occurs inside the blog_details view in the row:
blog= Blog.objects.get(slug=slug)
You should debug this part of the code and determine why you can't find the Blog instance by slug.

It's quite a wild guess as I'm not reproducing your code but in my opinion something with your slug seems wrong.
First change the following line:
blog_obj.slug = slugify(title + '-' + str(uuid.uuid4()))
see: https://docs.djangoproject.com/en/4.0/ref/utils/#django.utils.text.slugify
then change the following:
<p>{{blog.blog_content|capfirst|truncatewords:100}}Read More</p>
(remove slugify in the template)
Let me know if this worked. Also, if you need help with class based views, just let us know.

Related

Django: How to parse slug from url typed in address bar?

I am trying to simulate Google's behavior where the user types something on the address bar of the browser and the Django server checks for any exact matches in the database. If so, a detailview of the object is rendered. If not an exact match, then a list of matches on substrings are rendered with ListView.
This behavior works fine when the user types into a search form. For instance, when the user just types the letter 'j' in the search form and hits submit, the Django server matches on 3 objects in the data base 'Django, Java, node.js' and renders this list through ListView. If there is an exact match, say the user typed 'java', then the Django server renders details about the object 'java' in a Detail view.
However, I could not figure out how to derive the same behavior when applied to what the user types on the address bar of the browser. If the user happens to type just the exact spelling of an item in the db, the details of the item is rendered, otherwise we get a 404 error.
The relevant segments of the html form, urls.py, and views.py are displayed below
<form method="GET" action="{% url 'searchwiki' %}">
<input class="search" type="text" name="q" placeholder="Search Encyclopedia">
</form>
urls.py :
urlpatterns = [
path("", views.EntryListView.as_view(), name="index"),
path("entries/",views.EntryListView.as_view(),name='entries'),
path("entry/<int:pk>",views.EntryDetailView.as_view(),name="entry_detail"),
path("<int:pk>", views.EntryDetailView.as_view(), name="path_entry-detail"),
# path("<slug:subject>",views.get_obj_orlist),
path("<slug:subject>",views.EntryDetailView.as_view()),
path("random/",views.randompage,name="randompage"),
path("searchwiki/",views.searchwiki,name="searchwiki"),
]
views.py :
from django.urls import path
from . import views
from .models import Entry
from django.shortcuts import get_object_or_404, render, redirect
from django.views import generic
from django.views.generic.edit import CreateView, UpdateView, DeleteView
def searchwiki(request):
searchtoken = request.GET.get('q')
try:
entry = Entry.objects.get(subject=searchtoken)
except Entry.DoesNotExist:
entries = Entry.objects.filter(subject__icontains=searchtoken)
print("Inside exception code. qset size is ",len(entries))
return render(request, 'wikiencyc/searchencyc.html','entries':entries,'searchtoken':searchtoken})
return redirect(entry)
def get_obj_orlist(request):
model = Entry
slug_field = 'subject'
slug_url_kwarg = 'subject'
# below is the solution if it works
slug = kwargs.get(slug_url_kwarg)
try:
entry = Entry.objects.get(subject=slug)
except Entry.DoesNotExist:
entries = Entry.objects.filter(subject__icontains=slug)
return render(request, 'wikiencyc/searchencyc.html', {'entries':entries,'searchtoken':slug} )
return redirect(entry)
class EntryDetailView(generic.DetailView):
model = Entry
slug_field = 'subject'
slug_url_kwarg = 'subject'
The "searchwiki/" path in urls.py and the searchwiki(request) function in views.py work perfectly together for said functionality in response to search form.
As for parsing the slug from the address bar, the EntryDetailView(generic.DetailView) does a perfect job for an exact match of the parsed slug in the database, but responds with a 404 exception to the screen instead of a list of substring matches.
My attempt at replicating the searchwiki function for the addressbar is the function get_obj_orlist(request). It fails because I could not figure out how to get the slug from the address bar and urlconf to said function. It is probably something very simple but after 2 days of searching through the Django server code and docs I am saying AARRGG!!! when I see args and kwargs. Any help is deeply appreciated. I am still struggling with regular expressions, so I would appreciate it if these can be avoided in the solution presentation.
I found the solution. As I had expected, it was a very trivial overlook. Just including subject as a parameter into the function allowed its use in the Entry model for querying purposes. The working function is depicted below.
def get_obj_orlist(request, subject):
model = Entry
try:
entry = Entry.objects.get(subject=subject)
except Entry.DoesNotExist:
entries = Entry.objects.filter(subject__icontains=subject)
return render(request, 'wikiencyc/searchencyc.html', {'entries':entries,'searchtoken':subject} )
return redirect(entry)

Using category slug in url rather than pk

Right now I am able to show a product detail page by going to example.com/products/1 However I would like to be able to go example.com/<category_slug>/<product_slug>
views.py
def product_detail(request, pk):
product = Product.objects.get(pk=pk)
return render(request, 'main/product_detail.html', {'product': product})
root urls.py
from main.views import product_detail
path('products/<int:pk>/', product_detail, name='product-detail'),
In your Product model you would need something like this:
class Product(model.Models):
slug = models.CharField(max_length=255)
# Other fields
Then in your view:
from django.http import HttpResponseNotFound
def product_detail(request, slug):
try:
product = Product.objects.get(slug=slug)
except Product.DoesNotExist:
return HttpResponseNotFound()
return render(request, 'main/product_detail.html', {'product': product})
In your urls.py file:
from main.views import product_detail
path('products/<str:slug>/', product_detail, name='product_detail'),
It's the exact same as using a PK, you just use a string instead. The string just has to be stored in the database (it kind of acts like a "primary key" in that sense). It may also make sense to make it a unique field. Notice that I wrapped the .get() method in a try and except. This will be very useful for people typing random things into their request.
EDIT: Technically, you should also add the flag unique=True to your slug field. This will prevent .get() from breaking.

How I should testing Django views with unique slug

I try write tests.py to my views.
I have issue with write a good test to view with slug.
views.py:
def post_detail(request, slug):
post = Post.objects.get(slug=slug)
context = {'post': post}
template = 'post/post_detail.html'
return render(request, template, context)
Url looks like : post/slug_name, and slug is unique for every post.
I try:
tests.py
class PostDetailTestCase(TestCase):
def test_post_detail_(self):
test = Post(title='poost', description="posting", category="letstest", slug='django')
response = self.client.get(reverse('board_detail', args=(self.slug,)))
self.assertEqual(response.status_code, 200)
Run test error:
response = self.client.get(reverse('post_detail', args=(self.slug,
AttributeError: 'PostDetailTestCase' object has no attribute 'slug'
How I should repair it? Thanks in advance.
In tests.py self currently refers to the class PostDetailTestCase and that class has no slug. You've almost created a post in the db that django can access.
What you need to do however is to use the following. You need to use the objects.create method in the following way.
test = Post.objects.create(
title='poost',
description="posting",
category="letstest",
slug='django'
)
If you then replace self with test things should work out.
response = self.client.get(reverse('board_detail', args=(test.slug,)))

Changing value type doesn't change ValueError invalid literal for int() with base 10: ''

I'm very new to Python and am building a basic blog in django. I am trying to enable editing of individual blog posts. I have to 'get' these individual blog posts so I can edit them. So far, the system isn't liking my '.get' method and shows me a ValueError. I have tried changing the value type to int, str, float, even complex. It all either returns the same or says it doesn't like 'id' or even 'pk' if I change it to that.
Here is the code.
views.py
from django.shortcuts import render
from blogs.models import BlogPost
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .forms import PostForm
def index(request):
"""The home page for blogs"""
blogposts = BlogPost.objects.order_by('date_added')
context = {'blogposts': blogposts}
return render(request, 'blogs/index.html', context)
def blogpost(request, blogpost_id):
"""Show a single post"""
postings = BlogPost.objects.get(id=blogpost_id)
context = {'postings': postings}
return render(request, 'blogs/blogpost.html', context)
def new_post(request):
"""Writ a new post to the blog"""
if request.method != 'POST':
# No data submitted; create a blank form.
form = PostForm()
else:
# POST data submitted; process data
form = PostForm(data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('blogs:index'))
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_entry(request, entry_id):
"""Edit an existing entry"""
entry = BlogPost.objects.get(id=entry_id)
if request.method != 'POST':
# Initial request; pre-fill form with the current entry
form = PostForm(instance=entry)
else:
# POST data submitted; process data
form = PostForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('blogs:blogpost', args[entry_id]))
context = {'entry': entry, 'form': form}
return render(request, 'blogs/edit_entry.html', context)
If you'll notice, under def blogpost(request, blogpost_id):, I was able to employ the .get method in the same exact way and it was successful. What's more, the .get should work as an int anyway since the link is a whole number.
models.py
from django.db import models
class BlogPost(models.Model):
"""A blog post"""
title = models.CharField(max_length=200)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a string rep of model"""
return (str(self.title + " : " + self.text))
urls.py
"""URL Configs for app blogs"""
from django.conf.urls import url
from blogs import views
urlpatterns = [
#Home page
url(r'^$', views.index, name='index'),
#Individual Postings Pages
url(r'^(?P<blogpost_id>\d+)/$', views.blogpost, name='blogpost'),
#New Post Page
url(r'^new_post$', views.new_post, name='new_post'),
#Page for editing a post
url(r'^edit_entry/(?P<entry_id>)/$', views.edit_entry, name='edit_entry'),
]
For the
(?P<entry_id>)/$', I did take out the portion,\d+ , because the system read the '\' back as '\\' so I took it out.
forms.py
from django import forms
from .models import BlogPost
class PostForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['text']
labels = {'text':''}
widgets = {'text': forms.Textarea(attrs={'cols':80})}
What can I do to isolate and get the specific posts to edit them?
Thanks to anyone who answers this, in advance.
========================================================================
#Alasdair
I did add \d+ to the url and this is what I received...
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/edit_entry//
Using the URLconf defined in blog.urls, Django tried these URL patterns, in this order:
^admin/
^ ^$ [name='index']
^ ^(?P<blogpost_id>\d+)/$ [name='blogpost']
^ ^new_post$ [name='new_post']
^ ^edit_entry/(?P<entry_id>\d+)/$ [name='edit_entry']
The current URL, edit_entry//, didn't match any of these.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
Also, when I do that, it changes the behavior of the individual blog post. I get this response of the detailed view of the original post:
Exception Type: NoReverseMatch
Reverse for 'edit_entry' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['edit_entry/(?P<entry_id>\\d+)/$']
{% block content %}
<p>This is supposed to be for one post</p>
<p>{{ postings }}</p>
<p>Edit entry:</p>
edit entry
{% endblock content %}
The exception message you get is because you are trying to parse the empty string as an integer int(""). That operation makes no sense. The id pattern in the url should be at least one character.
(?P<entry_id>) is a completely useless pattern, since it contains no characters. It will always match an empty string '' and pass that to your view function.
(?P<entry_id>)/$, I did take out the portion,\d+ , because the system read the \ back as \\ so I took it out.
That's how it's supposed to work. There's no reason to take anything out.

Django seems to be caching?

I'm running Django 1.2.1 for my personal website with a blog. It's all fine and dandy, but I've found that all the browsers I've tried (Firefox, Chromium, Opera) are caching webpages, which of course is a problem for other users viewing my blog (being that it won't load new posts up unless they empty their cache or force refresh the page). I didn't have this problem when my site ran on PHP, so how would I go about fixing this seemingly Django-related problem?
I've only been working with Django for about a week or so, so I don't really know where abouts I should be looking to fix something like this. Thanks in advance!
The way I do each page (and each blog post) is as a Page/Post object respectively so I can use the admin interface without having to write my own. Although the issue is happening for both situations, I'll just give the Post class for now:
class Post(models.Model):
author = models.ForeignKey(User, default=User.objects.get(username='nathan'))
status = models.ForeignKey(Status, default=Status.objects.get(text='Draft'))
date = models.DateTimeField(default=datetime.datetime.now())
title = models.CharField(max_length=100)
post = models.TextField()
categories = models.ManyToManyField(Category)
def __unicode__(self):
return u'%s' % self.title
def link(self):
return u'/blog/post/%s' % self.title
class Meta:
ordering = ['-date']
And here's my urls.py:
from django.conf.urls.defaults import *
from django.views.generic import list_detail
from feeds import PostFeed
from models import Post
blog_posts = {
'queryset': Post.objects.filter(status__text__exact='Published'),
}
urlpatterns = patterns('getoffmalawn.blog.views',
(r'^$', list_detail.object_list, blog_posts),
(r'^archive/(\d{4})$', 'archive'),
(r'^rss/$', PostFeed()),
(r'^search/$', 'search'),
(r'^tag/(.+)/$', 'tag'),
(r'^post/(.+)/$', 'post'),
)
If you guys would like to see the code from views.py, just ask and I'll throw that up too.
Edit:
Here's the views.
view.py for the blog App:
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, redirect
from django.core.context_processors import csrf
from django.db.models import Q
from models import Post, Category
def post(request, title):
post = Post.objects.get(title=title)
c = locals()
c.update(csrf(request))
return render_to_response('blog/post_detail.html', c)
def blog_detail(request, blog_id):
post = get_object_or_404(Post, pk=blog_id)
return list_detail.object_detail(request, queryset=Post.objects.all(), object_id=blog_id)
def archive(request, month, year):
pass
def search(request):
if request.method == 'GET':
query = request.GET['q']
object_list = Post.objects.filter(Q(post__icontains=query) | Q(title__icontains=query), status__text__exact='Published')
return render_to_response('blog/post_list_sparse.html', locals())
def tag(request, tag):
object_list = Post.objects.filter(categories__text__exact=tag, status__text__exact='Published')
return render_to_response('blog/post_list.html', locals())
The problem was that it really was browser-based caching, as I was told by a member on the Django-users mailing list. The reason I didn't see this problem in PHP is that it was sending cache suppression headers.
The solution was to add the #never_cache decorator to the relevant views.
Here is the documentation for caching in django.
https://docs.djangoproject.com/en/1.2/topics/cache/
Not ideal, but you can make all of the pages tell the browsers not to cache anything, to see if that helps.
https://docs.djangoproject.com/en/1.2/topics/cache/#controlling-cache-using-other-headers

Categories