Handling errors 404/500 in Django - django

There is a little problem with my Django application: my project is a blog with several posts. You can access the first post by typing localhost:8000/blog/post/1 in the URL bar. To read the post no. X you have to type localhost:8000/blog/post/X. So I need to display a custom "Error 404" page when an inexistant post is requested (for example localhost:8000/blog/post/32 if there are only 3 posts available). The problem is, instead of throwing a 404 error, it throws a Server Error (500) error however I never coded something to throw this kind of error.
Here is the concerned code parts, but not my full code which I think is useless.
Project name is red_pillers, app name is blog.
in red_pillers/settings.py
DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
red_pillers/urls.py
from django.contrib import admin
from django.urls import path, re_path, include
from django.conf.urls import handler404
from . import views
handler404 = 'red_pillers.views.handler404'
urlpatterns = [
re_path('^blog/', include('blog.urls')),
re_path('^$', views.home),
re_path('^admin/', admin.site.urls),
]
red_pillers/views.py
from django.shortcuts import render
def home(request):
return render(request, 'home.html')
def handler404(request):
return render(request, 'errors/404.html', {}, status=404)
blog/pycode/post.py
from django.http import Http404
class Post:
POSTS = [
{'id': 1, 'title': 'First Post', 'body': 'This is my first post'},
{'id': 2, 'title': 'Second Post', 'body': 'This is my second post'},
{'id': 3, 'title': 'Third Post', 'body': 'This is my third post'},
]
#classmethod
def all(cls):
return cls.POSTS
#classmethod
def find(cls, id):
try:
return cls.POSTS[int(id) - 1]
except:
raise Http404('Error 404...')
EDIT: added more code
blog/urls.py
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('^$', views.index),
re_path('^posts/(?P<id>[0-9]+)$', views.show),
]
blog/views.py
from django.shortcuts import render
from .pycode.post import Post
def index(request):
posts = Post.all()
return render(request, 'blog/index.html', {'posts': posts})
def show(request, id):
post = Post.find(id)
return render(request, 'blog/show.html', {'post': post})

Use get_object_or_404, which will redirect you if it doesn't exist.

Related

Django redirect another view from another app form

contact/views.py
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect
from .forms import ContactForm
def contactView(request):
if request.method == 'GET':
form = ContactForm()
else:
form = ContactForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['subject']
from_email = form.cleaned_data['from_email']
message = form.cleaned_data['message']
try:
send_mail(subject, message, from_email, ['admin#example.com'])
except BadHeaderError:
return HttpResponse('Invalid header found.')
# return redirect('success')
return redirect('PostList') #another view from another app
return render(request, "contact.html", {'form': form})
# def successView(request):
# return HttpResponse('Success! Thank you for your message.')
contact/urls.py
from django.contrib import admin
from django.urls import path
from .views import contactView
urlpatterns = [
path('contact/', contactView, name='contact'),
# path('success/', successView, name='success'),
]
blog/views.py
from django.views import generic
from .models import Post, PostImage
# Create your views here.
class PostList(generic.ListView):
queryset = Post.objects.filter(status=1).order_by('-created_on')
template_name = 'index.html'
class PostDetail(generic.DetailView):
model = Post
template_name = 'post_detail.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet of all the books
# context['image_list'] = PostImage.objects.all()
# context['image_list'] = self.get_object().postimage_set.all()
context['image_list'] = PostImage.objects.filter(post__slug=self.kwargs.get('slug'))
return context
blog/urls.py
from . import views
from django.urls import path
urlpatterns = [
path('', views.PostList.as_view(), name='home'),
path('<slug:slug>/', views.PostDetail.as_view(), name='post_detail'),
]
I need the following in the SIMPLEST DRY manner possible; how do I write this redirect inside contact/views.py?
return redirect('PostList') #another view from another app
PostList is a class-based view from another app called blog. It is the homepage essentially.
for reference..
https://ordinarycoders.com/blog/article/django-messages-framework
In your project folder (eg, my_project/my_project) you should have a urls.py with something like this
path("admin/", admin.site.urls),
path("", include("blog.urls")),
path("", include("contact.urls"))
This allows django to look through all url files in the order listed. So long as all your url names and patterns are unique, then your view should be able to simply do
from django.shortcuts import redirect
from django.urls import reverse
return redirect(reverse('home'))
'home' being the name value of the ListView.
(NB: if you have various applevel urls.py files with path(''... django will take the first one it hits)

My django admin page gives Page not found (404)

my project was running ok I used my admin page at it was all all right today I tried to open it and it gives a Page not found (404)
No Product matches the given query.
Request Method: GET
Request URL: http://127.0.0.1:8000/admin
Raised by: store.views.product_detail
No Product matches the given query.
Request Method: GET
Request URL: http://127.0.0.1:8000/admin
Raised by: store.views.product_detail
I havent touched the store app or project files at all at it was waking just fine yesterday now i cannot access admin page
project urls
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('store.urls', namespace='store')),
path('basket/', include('basket.urls', namespace='basket')),
path('account/', include('account.urls', namespace = 'account')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
store urls
from django.urls import path
from . import views
app_name = 'store'
urlpatterns = [
path('', views.product_all, name='product_all'),
path('<slug:slug>', views.product_detail, name='product_detail'),
path('shop/<slug:category_slug>/', views.category_list, name='category_list'),
]
store views
from urllib import request
from django.shortcuts import get_object_or_404, render
from store.context_processors import categories
from .models import Category, Product
def product_all(request):
products = Product.products.all()
return render(request, 'store/home.html', {'products': products})
def category_list(request, category_slug=None):
category = get_object_or_404(Category, slug=category_slug)
products = Product.objects.filter(category=category)
return render(request, 'store/products/category.html', {'category': category, 'products': products})
def product_detail(request, slug):
product = get_object_or_404(Product, slug=slug, in_stock=True)
return render(request, 'store/products/single.html', {'product': product}) ```
context_processors.py wicht i have includet in my project settings
from .models import Category
def categories(request):
return {
'categories': Category.objects.all()
}
This is the code that causes the error
path('<slug:slug>', views.product_detail, name='product_detail'),
Change it to
path('detail/<slug:slug>/', views.product_detail, name='product_detail'),
The product_detail just overwrites the admin URL

Django - missing 1 required positional argument: '_id'

im getting an error
BlogDetailView() missing 1 required positional argument: '_id'
when im trying to access the function BlogDetailView.
views.py :
from django.http.response import Http404
from .models import BlogModel,CommentModel
from .forms import SearchForm,CommentForm
from django.shortcuts import render,redirect
def BlogDetailView(request,_id):
try:
data = BlogModel.objects.get(id = _id)
comments = CommentModel.objects.filter(blog = data)
except BlogModel.DoesNotExist:
raise Http404('Data does not exist')
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
Comment = CommentModel(your_name= form.cleaned_data['your_name'],
comment_text=form.cleaned_data['comment_text'],
blog=data)
Comment.save()
return redirect(f'/blog/{_id}')
else:
form = CommentForm()
context = {
'data': data,
'form': form,
'comments': comments,
}
return render(request,'Test_one/detailview.html',context)
urls.py :
from django.conf.urls import url
from django.urls.conf import path
from blogapp.views import BlogDetailView, BlogListView
from . import views
app_name = "Blogapp"
urlpatterns = [
url(r'^blogs/', views.BlogDetailView, name="blogs"),
url(r'^blog/<int:_id>', views.BlogListView, name="blog"),
]
Can anyone solve this problem?
I think you wrote code wrongly, logically a blog list doesn't need an id to fetch (you want all blog posts so probably don't need id) and you need to fetch a specific blog post so you need an id to fetch this. so I think this is the right code that you tried to write:
from django.conf.urls import url
from django.urls.conf import path
from blogapp.views import BlogDetailView, BlogListView
from . import views
app_name = "Blogapp"
urlpatterns = [
url(r'^blogs/<int:_id>', views.BlogDetailView, name="blogs"),
url(r'^blog/', views.BlogListView, name="blog"),
]

How do I fix the NoReverseMatch Django error?

I am trying to complete a CS50 Project, I want to render a HTML page, the template is in respective templates/encyclopedia directory.
The error page for url 127.0.0.1:8000/wiki/HTML says NoReverseMatch at wiki/HTML.
Reverse for 'edit' not found. 'edit' is not a valid view function or pattern name.
The responsible URLS.py are "wiki/<str:search>" and "wiki/random".
I'm sorry but I don't want to post this long code here but I am stuck at this problem for weeks now.
I have tried many ways don't know what's wrong with this code.
The below is my URLS.py, the projects index url includes the below urls:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("wiki/newpage", views.newpage, name="newpage"),
# path("wiki/<str:edit>/edit", views.edit, name="edit"),
path("wiki/random", views.random, name="random"),
path("wiki/<str:search>", views.search, name="search"),
path("wiki/", views.find, name="find")
]
The below is my VIEWS.py:
from django.shortcuts import render, redirect
from django.contrib import messages
import markdown2 as md
from . import util
from django import forms
import re, random as rand
def index(request):
return render(request, "encyclopedia/index.html", {
"entries": util.list_entries()
})
def search(request, search):
if search in util.list_entries():
html = md.markdown(util.get_entry(search))
return render(request, "encyclopedia/search.html", {
"search": search, "html": html
})
else:
return render(request, "encyclopedia/error.html")
def random(request):
randomPage = rand.choice(util.list_entries())
if randomPage in util.list_entries():
html = md.markdown(util.get_entry(randomPage))
return render(request, "encyclopedia/search.html", {
"random": randomPage, "html": html
})
else:
return render(request, "encyclopedia/error.html")
def find(request):
if request.method == "GET":
query = request.GET.get('q')
for queryMatch in util.list_entries():
if query.casefold() == queryMatch.casefold():
html = md.markdown(util.get_entry(query))
return render(request, "encyclopedia/search.html", {
"queryMatch": queryMatch, "html": html
})
regex = re.compile(query.casefold())
matchList = []
for a in util.list_entries():
if regex.match(a.casefold()):
matchList.append(a)
if not matchList:
matchList = util.list_entries()
return render(request, "encyclopedia/list.html", {
"match": matchList
})
class NewPageForm(forms.Form):
title = forms.CharField(label="Title")
content = forms.CharField(label="Markdown Content", widget=forms.Textarea(attrs={'cols': '100'}))
def newpage(request):
if request.method == "POST":
form = NewPageForm(request.POST)
if form.is_valid():
title = form.cleaned_data["title"]
content = form.cleaned_data["content"]
if title in util.list_entries():
messages.error(request, f"'{title}' page title already exists!!\nPlease type another title.")
return render(request, "encyclopedia/newpage.html", {
"form": form
})
else:
util.save_entry(title, content)
return redirect(f"/wiki/{title}")
else:
return render(request, "encyclopedia/newpage.html", {
"form": form
})
return render(request, "encyclopedia/newpage.html", {
"form": NewPageForm()
})
# def edit(request, edit):
# entry = util.get_entry(edit)
Have you include your app.urls in project.urls?
Including other URLconfs
Some example from Django tutorial:
polls/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
mysite/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]

How to make custom 404 page for the Detail view with <int:pk>, if the instance not found?

so the error is Page not found(404) when I am requesting the instance that does not exist. I would like to customize the 404 page, instead of displaying the general error.
Here is my new_wiki/urls
from django.urls import path
from . import views
from .views import IndexView, InstanceView, AddPostView, EditPost
urlpatterns = [
# path('', views.index, name="index")
path('', IndexView.as_view(), name="index"),
path('instance/<int:pk>', InstanceView.as_view(), name="instance"),
path('create_post/', AddPostView.as_view(), name="create_post"),
path('instance/edit/<int:pk>', EditPost.as_view(), name="edit_post")
]
And my InstanceView class
class InstanceView(DetailView):
model = Post
template_name = 'new_wiki/instance.html'
I have tried to use the solution from Django documentation:
def detail(request, post_id):
try:
p = Post.objects.get(pk=post_id)
except Post.DoesNotExist:
raise Http404("Poll does not exist")
return render(request, 'new_wiki/instance.html', {'post': p})
but it is still returning the same 404 page. Thank you
You can just render a page with a 404 status:
def detail(request, post_id):
try:
p = Post.objects.get(pk=post_id)
except Post.DoesNotExist:
return render(request, 'new_wiki/404error.html', status=404)
return render(request, 'new_wiki/instance.html', {'post': p})
If you want to specify a custom 404 page in general, you specify the handler404 [Django-doc] in the urls.py:
from django.urls import path
from . import views
from .views import IndexView, InstanceView, AddPostView, EditPost
urlpatterns = [
# path('', views.index, name="index")
path('', IndexView.as_view(), name="index"),
path('instance/<int:pk>', InstanceView.as_view(), name="instance"),
path('create_post/', AddPostView.as_view(), name="create_post"),
path('instance/edit/<int:pk>', EditPost.as_view(), name="edit_post")
]
handler404 = views.handler404
In the view you can then analyze the exception parameter and return a specific
# app/views.py
from django.http import HttpResponseNotFound
def handler404(request, exception):
data = exception.args
if data:
return HttpResponseNotFound(data[0])
return HttpResponseNotFound('some text')
This then works if you set the DEBUG setting [Django-doc] to False:
# settings.py
DEBUG = False
In that case the handler will be invoked when you raise a Http404.
Please use get_object_or_404 method
from django.shortcuts import get_object_or_404
def detail(request, post_id):
p = get_object_or_404(Post,pk=post_id)
return render(request, 'new_wiki/instance.html', {'post': p})
Please check this is working.