this is the first time I had to ask something at StackOverflow, I'm both excited and scared, I don't know why.
I'm writing a Django app that just hosts web posts. The page is divided into three (3) categories (Index, lkmi and chiqung). Each post has a category (lkmi or chiqung).
On the INDEX page, you can see all the posts.
On the LKMI page, you can see only the lkmi posts.
On the CHIQUNG page, you can see only the chiqung posts.
All is controlled just by ONE VIEW called "index_page", which receives an argument called "cat" that is the URL from one of the categories (index, lkmi, chiqung). Based on that it dictates which posts to load.
* NOW THE PROBLEM *
I can't find why, but I'm only having trouble loading the lkmi section. The index page and the chiqung_page loads perfectly, but I'm having a
"Page Not Found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/lkmi/
Using the URLconf defined in blog.urls, Django tried these URL patterns, in this order:
admin/
<cat> [name='index_page']
post/<int:pk> [name='post_detallado']
^ckeditor/
The current path, lkmi/, didn't match any of these.
"
I'll leave here the models, views and urls.
Models
Category
class Category(models.Model):
name = models.CharField(max_length=50)
presentation = RichTextUploadingField(default='')
order = models.IntegerField(null=True)
url = models.CharField(max_length=50,default='',null=False,blank=True)
class Meta:
verbose_name = ("Categoria")
verbose_name_plural = ("Categorias")
def __str__(self):
return self.name
def get_postes(self):
print('Entre get_postes')
if self.url == '/':
return Post.objects.all().order_by('-published_date')
else:
return Post.objects.filter(category=self.pk).order_by('-published_date')
Post
class Post(models.Model):
title = models.CharField(('Titulo'),max_length=50)
category = models.ForeignKey("core.Category", verbose_name=("Categoria"), null=True, on_delete=models.CASCADE)
creation_date = models.DateTimeField(auto_now = True)
published_date = models.DateTimeField(auto_now=False, auto_now_add=False)
content = RichTextUploadingField()
author = models.CharField(("Autor/a"), max_length=50, default='El Autor')
class Meta:
verbose_name = ("Post")
verbose_name_plural = ("Postes")
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("_detail", kwargs={"pk": self.pk})
View That Handles The Categorization
def index_page(request, cat):
print('function index_page')
print('cat ='+str(cat))
category = get_object_or_404(Category,url=cat)
print('get_object_or_404(Category,url=cat). Executed')
print(str(category))
postes = category.get_postes()
print('category.get_postes(). Executed')
return render(request, 'index.html',{'postes': postes,
'category': category})
URL file from the app
urlpatterns = [
path('admin/',admin.site.urls),
path('<cat>', views.index_page, name='index_page'),
path('post/<int:pk>', views.detailed_post, name='detailed_post'),
]
Index Page
It loads
Chiqung Page
It loads
LKMI Page
It doesn't load...
If i use python manage.py shell and look for the category using Category.objects.get(url='lkmi') it returns the desired Category. Based on the comments of the view, it doesn't even enter the view function, because in the console it doesn't output "function index_page", even though it is the first line of the function.
Also, if i try the url "**127.0.0.1:8000/lkmi" it gives
Using the URLconf defined in blog.urls, Django tried these URL patterns, in this order:
1. admin/ -
2. <cat> name='index_page'] -
3. post/<int:pk> [name='post_detallado'].
But if i just enter "127.0.0.1:8000/whatever" the error is just
No Categoria matches the given query.
So in this case it entered the function and it gave the 404 error of not finding a matching Category. I still can't understand why it doens't execute the view when i try to enter to the lkmi url..
Thank you very much, I hope someone can help me with this so I cant continue going.
Your class is called "Category", but you call get_object_or_404() on "Categoria"
View should be:
def index_page(request, cat):
categoria = get_object_or_404(Category,url=cat)
postes = categoria.get_postes()
return render(request, 'index.html',{'postes': postes,
'categoria': categoria})
Related
I trying to add slugs to my service page and my project page, but whenever I try to run my project page I get the Page not found (404)
No service found matching the query
Request Method: GET
Request URL: http://127.0.0.1:8000/project/
Raised by: pages.views.<class 'pages.views.ServiceDetail'>
Here's my class-based code
models.py
class Service(models.Model):
title = models.CharField(max_length=50)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/')
alt = models.CharField(max_length=60, blank=True)
icon = models.CharField(max_length=20)
description = RichTextField()
shortdesc = models.CharField(max_length=255)
slug = models.SlugField(null=False, unique=True)
created_date = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('service_detail', kwargs={'slug': self.slug})
class Project(models.Model):
title = models.CharField(max_length=50)
category = models.CharField(max_length=50)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/')
alt = models.CharField(max_length=60, blank=True)
client = models.CharField(max_length=50)
launched = models.CharField(max_length=50)
demands = models.CharField(max_length=50)
description = RichTextField()
shortdesc = models.CharField(max_length=255)
slug = models.SlugField(null=False, unique=True)
video_link = models.URLField(max_length=100)
created_date = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('project_detail', kwargs={'slug': self.slug})
urls.py
path('<slug:slug>/', views.ServiceDetail.as_view(), name='service_detail'),
path('project/<slug:slug>/', views.ProjectDetail.as_view(), name='project_detail'),
views.py
def project(request):
return render(request, 'project/project.html')
class ProjectDetail (generic.DetailView):
model = Project
template_name = 'project/project_detail.html'
def service(request):
return render(request, 'pages/service.html')
class ServiceDetail (generic.DetailView):
model = Service
template_name = 'pages/service_detail.html'
how can I re-route so that my project page can work out? any help would be grateful
Your url path in urls.py is pointing to path('project/slug:slug/',...), however you are requesting a page without the /slug:slug/ part being passed http://127.0.0.1:8000/project/ (slug part missing). Request http://127.0.0.1:8000/project/slug-name (replace slug-name with a valid slug) and see if it works.
Also see Razensteins answer
The error message has the following reason:
you make a call to "http://127.0.0.1:8000/project/"
your path statement is routing it to 'pages.views.ServiceDetail' - with url parameter slug="project"
path('<slug:slug>/', views.ServiceDetail.as_view(),
Inheritance of ServiceDetail -> DetailView -> BaseDetailView -> SingleObjectMixin (among others..)
as you make a GET request, method get() in BaseDetailView is called:
def get(...)
self.object = self.get_object()
method get_object() in SingleObjectMixin
try:
# Get the single item from the filtered queryset
obj = queryset.get()
except queryset.model.DoesNotExist:
raise Http404(_("No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
queryset.get() tries to find an item with slug="project" which does not exist in database and handles the resulting excpetin whit the 404 response that you get as error message
So to avoid that the call to "http://127.0.0.1:8000/project/" is going to be routed by
path('<slug:slug>/', views.ServiceDetail.as_view().....
you need to change the order of paths:
path('project/<slug:slug> ....
path('<slug:slug> ....
and make a call like "http://127.0.0.1:8000/project/your_project_slug"
With you current order, 'project' is interpreted as slug, because paths are matched one after the other.
I am building a Blog App and I am trying to implement a feature -
In which a user can rate blogs in one page and after user click Save Rate then user will redirect to next review blog page and user will ratenext blog.
But it is not redirecting to next rate blog page.
models.py
class Blog(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=500)
Rating_Choice = [('1','1'), ('2','2')]
class Rate(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
ratings = models.CharField(max_length=1, choices=Rating_Choice)
views.py
def rate_blog_post(request, blog_id):
obj = get_object_or_404(Blog, pk=blog_id)
next_blog = Blog.objects.filter(rate__ratings=None)
if request.method == 'POST':
form = Form(data=request.POST)
if form.is_valid():
post= form.save(commit=False)
post.user = request.user
post.blog = data
post.save()
# redirect here
return redirect('rate_blog_post', pk=data.id)
else:
form = Form()
context = {'obj':obj, 'form':form}
return render(request, rate_blog_post.html', context)
urls.py
path('rate_blog_post/<int:blog_id>/', views.rate_blog_post, name='rate_blog_post'),
Form is working fine, it is saving the ratings
What have i tried so far ? :
I have tried using a next_blog like :-
return redirect('rate_blog_post', rate_blog_post=blog_id)
But it showed
Reverse for 'rate_blog_post' with keyword arguments '{'pk': 2}' not found
NOTE :- next_blog contains multiple blogs, But i didn't find any other way to use like get_object_or_404(Blog,pk=blog_id, rate__ratings =None), So it will redirect to next blog post id which have rating = None
Than i tried get_object_or_404(Blog,pk=blog_id, rate__ratings =None)
Than it shows .
Reverse for 'rate_blog_post' with keyword arguments '{'pk': 3}' not found. 1 pattern(s) tried: ['rate_blog_post/(?P<blog_id>[0-9]+)/$']
I have tried many times but did't worked for me.
I will really appreciate your Help. Thank You
So, i made a choices of reviews. And User will redirect to next post which have choice None,
Problem lies here :
next_blog = Blog.objects.filter(rate__ratings=None)
return redirect('rate_blog_post', pk=data.id)
First :
Query a single blog you want to visit next, not multiple
next_blog = Blog.objects.filter(rate__ratings="").order_by('id')[0]
Second :
use pk=next_blog.id while redirecting
return redirect('rate_blog_post', blog_id=next_blog.id)
ratings = models.CharField(max_length=1, choices=Rating_Choice, default="")
This should resolve the issue
I've started using Django 2.0 and Python 3.6.3 to develop a website which will display customized "Posts", as in a blog Post.
I want the user to be able to click a button that basically says "Random Post". This button will take them to a template which loads a random blog post.
Here's my Post model:
class Post(models.Model):
post_id = models.AutoField(primary_key=True)
... other fields
... other fields
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
Here are some relevant views:
class PostListView(ListView):
model = Post
template_name = 'blog/post_list.html'
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post_detail.html'
Here is my problematic view:
import random
def random_post(request):
post_ids = Post.objects.all().values_list('post_id', flat=True)
random_obj = Post.objects.get(post_id=random.choice(post_ids))
context = {'random_post': random_obj,}
return render(request, 'blog/random_post.html', context)
Here I am trying to create a Values List of all post_id values for the Post model. Then I'm trying to get a random choice from this Values List, which would be a random id. Then I'm trying to create a context and render a template using this logic.
Here are relevant urlpatterns:
urlpatterns = [
path('post/<int:pk>/',
views.PostDetailView.as_view(),name='post_detail'),
path('post/random/<int:pk>', views.random_post, name='random_post'),
Needless to say this is not working.
If I leave off the "int:pk" it renders a blank template with no data - no blog Post. If I include the , it causes an error - No Arguments Found. I assume that no data is being queried in the view, or the data isn't being properly sent from the view to the template.
I am new to Django. I appreciate your help!
For the behaviour you want, your URLs should be:
urlpatterns = [
path('post/random/', views.random_post, name='random_post'),
path('post/<int:pk>/',
views.PostDetailView.as_view(),name='post_detail'),
]
and your random_post view is:
def random_post(request):
post_count = Post.objects.all().count()
random_val = random.randint(1, post_count-1)
post_id = Post.objects.values_list('post_id', flat=True)[random_val]
return redirect('post_detail', pk=post_id)
This makes two queries - one to get the count of all posts, and one to get ID of the post in the random position. The reason for doing this is that then you don't have to get all of the IDs from the database - if you have thousands of posts, that would be very inefficient.
Here's the view that works.
def random_post(request):
post_count = Post.objects.all().count()
random_val = random.randint(0, post_count-1)
post_id = Post.objects.values_list('post_id', flat=True)[random_val]
return redirect('post_detail', pk=post_id) #Redirect to post detail view
I'm hoping this is just an issue of my poor regex understanding.
I'm attempting to use the exact code on Django 1.9's generic views to build a blog and personal site, and, down to the testing, here's where I run into trouble:
def test_post_page(self):
post = PostModelFactory()
first_post = Post.objects.all()[0]
post_url = first_post.get_absolute_url()
print(post_url)
response = self.client.get(post_url, follow=True)
self.assertEqual(response.status_code, 200)
So, through that print statement, I determined models.Post.get_absolute_url() was returning my homepage URL. Here's models.py:
class Post(models.Model):
title = models.CharField(max_length=200)
subtitle = models.CharField(max_length=200, default="")
pub_date = models.DateTimeField(auto_now_add=True)
text = models.TextField()
slug = models.SlugField(max_length=40,unique=True)
def get_absolute_url(self):
return "%s/" % (self.slug)
Should it come up, I copied down what the generic views documentation has, so my Detailview in /blog/urls.pyis as follows:
url(r'^(?P<slug>[-\w]+)/$', PostDetailView.as_view(), name='post-detail'),
Same of views.py:
class PostDetailView(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['now'] = timezone.now()
return context
As far as I can tell, my get_absolute_url() function is simply not doing what I think it's doing, let alone what the regex in urls.py expects it to do.
Also: Is there anyone who can fully explain how slugfield works? I know it's a keyword generator to create a url, but I'm not sure how it works (or doesn't, as in this example).
Then, finally, in both a tutorial that I'm quasi-following alongside the documentation, and the documentation, itself, I'm not fully understanding where the variable names in templates are coming from (my understanding is that the request hit's the URL, which generates the data from views.py). The "ListView" object in the template shares the model name, "post" (or "article" in the documentation), where its pageview at the bottom is accessed simply through "page_obj", and the "DetailView" object is simply called "object". I also may be having a problem with paginating my ListView, ( which is identical to the documentation example, but with the extra line paginate_by = 2 right above get_context_data.
Thank you.
EDIT:
I've included PostModelFactory:
class PostModelFactory(DjangoModelFactory):
class Meta:
model = Post()
django_get_or_create = (
'title',
'subtitle',
'text',
'pub_date',
)
title = 'This is a test.'
subtitle = 'This is only a test.'
text = 'Madness? This is Sparta.'
pub_date = timezone.now()
def __init__(self):
self.save()
Edit: The issue turned out to be the lack of a slug in the PostModelFactory.
Ideally, you should use reverse in get_absolute_url, instead of hardcoding it.
from django.core.urlresolvers import reverse
class Post(models.Model):
...
def get_absolute_url(self):
return reverse('post-detail', args=[self.slug])
If you do hardcode the URL, it should contain a leading slash.
def get_absolute_url(self):
return "/%s/" % (self.slug)
If first_post.get_absolute_url is returning the homepage url with your current get_absolute_url, that suggests that the slug is an empty string.
I'm trying to get something in Django, already for hours but without success. However I'm trying to use friendly urls like 'my-post-title-1234', where the number at the end is the post's id and the rest before that is the post's title. I got the url by using the slug and the id and I can retrive both in the view. So I check if ID exists and if it exists I do the rest, and if it doesn't exist I do 404 DoesNotExist. Inside the model I generated slug field and slugified title.
Everything works so far except one thing: User is able to write bla-bla-bla-1234 and it will still show him same data (since id exist). What I would like is following:
If user type in 'bla-bla-bla-1234' I would like to redirect him to correct slug 'my-post-title-1234'.
This is how my url looks like:
url(r'^(?P<slug>[-\w\d]+)-(?P<post_id>\d+)/$', views.post, name='post')
This is my model:
class Post(models.Model):
post_title = models.CharField(max_length = 125)
text = models.TextField()
slug = models.SlugField(null = False, blank = True)
def __str__(self):
return self.post_title
def save(self, *args, **kwargs):
self.slug = slugify(self.post_title)
super(Post, self).save(*args, **kwargs)
This is from my view:
def post(request, slug, post_id):
try:
post = Post.objects.get(id = post_id)
except Post.DoesNotExist:
raise Http404("Post does not exist")
return HttpResponse(post_id)
So the question is: how do I redirect(change url) to the correct slug from 'bla-bla-bla-1234' to 'my-post-title-1234', if user type in slug incorrectly while id is still good.
Thanks a lot.
Seems like you just need to check if the slug is correct, and if not do a redirect.
from django.shortcuts import get_object_or_404, redirect
def post(request, slug, post_id):
obj = get_object_or_404(Post, pk=post_id)
if obj.slug != slug:
return redirect('post', slug=obj.slug, post_id=obj.pk)
Note that there's a built-in shortcut for your first four lines: get_object_or_404. Also, be aware that calling an object within the function the same name as the function itself can lead to confusion; avoid doing that (which is why I've use obj above.)
In Django redirect comes with parameters, you can simply pass the slug in redirect by putting a ",".
return redirect("post",slug=slug)