I am using Django 1.4.5.
I get an error when I access the detail of entry via admin's page.
"NoReverseMatch at /admin/r/12/1/": Reverse for 'detail' with
arguments '()' and keyword arguments '{'category': u'category',
'slug': u'entry-test'}' not found
And get nothing/blank page when access the detail of entry on front's page (/category/entry-test/).
And what's the right of models & URLname pattern if I want to access the entry detail via sub-category (/category/subcategory/entry-test/)?
Model snippet:
class Entry (models.Model):
title = models.CharField()
slug = models.SlugField()
category = models.ForeignKey('entry.Category')
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
return ('entry.views.detail', (), {'category': self.category.slug, 'slug': self.slug})
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
return super(Entry, self).save(*args, **kwargs)
class Category(models.Model):
title = models.CharField()
slug = models.SlugField()
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
def __unicode__(self):
if self.parent:
return self.parent.title, self.title
return self.title
#permalink
def get_absolute_url(self):
return ('entry.views.category', (), {'slug': self.slug})
Views snippet:
def category(request):
category = Category.objects.all()
return render_to_response('category.html', locals(), context_instance=RequestContext(request))
def list(request, slug_id):
category = get_object_or_404(Category, slug=slug_id)
list = Entry.objects.filter(category=category)
return render_to_response("list.html", locals(), context_instance=RequestContext(request))
def detail(request, category_id, slug_id):
entry = Entry.objects.filter(slug=slug_id)
category = Category.objects.filter(slug=category_id)
return render_to_response('detail.html', locals(), context_instance=RequestContext(request))
URLs snippet:
urlpatterns = patterns('entry.views',
(r'^$', 'category', name='entry-category'),
url(r'^(?P<slug_id>[-\w]+)/$', 'list', name='entry-list'),
url(r'^(?P<category_id>[-\w]+)/(?P<slug_id>[-\w]+)/$', 'detail', name='entry-detail'),
Template snippet:
category.html
<ul>
{% for category in category %}
<li>{{ category.title }} ({{ category.entry_set.all.count }})</li>
{% endfor %}
</ul>
list.html
<ul>
{% for entry in list %}
<li>{{ entry.title }}</li>
{% endfor %}
</ul>
detail.html
<ul>
{% for entry in entry.category %}
<li>{{ entry.title }}
<br />{{ entry.description }}</li>
{% endfor %}
</ul>
Where and what I could be doing wrong?
If any one can help I'd appreciate it! Please help me.
Your keyword arguments for the url are category_id and slug_id, but you are passing in category and slug in your get_absolute_url method. This version should work:
#models.permalink
def get_absolute_url(self):
return ('entry.views.detail',
(), {'category_id': self.category.slug, 'slug_id': self.slug})
Also consider renaming your arguments. id is generally numeric and slug is alphanumeric.
For your blank page problem (from your comment):
Your URL /category/entry-test/ - this will map to your detail view if the snippet your pasted in your question is in your main urls.py. If you have no matching results (the .filter() call has no results), you'll see a "blank" page, because the <ul> will not have any li elements.
If in your main urls.py, you have something like url('^category/', include(some.other.urls)), then the URL will map to your list view, and you have the same issue - the .filter() is not returning any results, and hence you see a "blank" page.
I do little mistake on detail template:
<ul>
{% for entry in entry %}
<li>
{{ entry.title }}
<br />
{{ entry.description }}
</li>
{% endfor %}
</ul>
The problem is solved now.
Related
I am building simple blog with posts and posts categories.
I would like to add links to posts categories to header and footer, so they appear on every page, not just home page (as routable pages).
How do I go about it?
Category class as below:
class BlogCategory(models.Model):
title = models.CharField( # field name has to be 'title'
verbose_name='Name', max_length=30, unique=True)
slug = AutoSlugField( populate_from='title', editable=True)
panels = [
MultiFieldPanel([
FieldPanel("title"),
FieldPanel("slug"),
], heading="New Category"),]
def __str__(self):
return self.title
Code for routable page:
class BlogIndexPage(RoutablePageMixin, Page):
class Meta:
verbose_name = "Blog Index Page"
template = "blog/blog_index_page.html"
parent_page_types = ["wagtailcore.Page"]
subpage_types = ["blog.PostArticlePage"]
max_count = 1
# context ------------------------------
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
all_posts = (
BlogDetailPage.objects.live().public().order_by("-first_published_at")
)
context["posts"] = all_posts
#route(r"^category/(?P<cat_slug>[-\w]*)/$", name="category_view")
def category_view(self, request, cat_slug):
context = self.get_context(request)
try:
category = BlogCategory.objects.get(slug=cat_slug)
except Exception:
return redirect(self.url)
if category is None:
return redirect('/')
context["posts"] = (BlogDetailPage.objects.live().public().filter(categories__in=[category]))
return render(request, "blog/blog_view_page.html", context)
Try this from here :
{% regroup object_list by category as post_list %}
<ul>
{% for post_category in post_list %}
<li>{{ post_category.grouper }}
<ul>
{% for post in post_category.list %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
You may have to modify it a bit but the principal is the same.
The regroup tag is well explained in the Django docs and Wagtail docs clearly mention they support Django tags.
To add blog categories to header and footer:
First create a simple template tag
register = template.Library()
#register.simple_tag()
def get_categories():
return BlogCategory.objects.all()
Next add following code to header and footer
{% load blog_tags %}
{% get_categories as categories %}
<nav>
<ul>
{% for cat in categories %}
<li>{{ cat.title }}</li>
{% endfor %}
</ul>
</nav>
Finally, reload the server.
lets's say that i have three categories (tutorials, news, jobs).
and i have class based views to list all posts, list posts by category and create new posts.
and sure post is the same model and fields to all categories.
my problem is :
if user was in category list template (let's say tutorial) .. i want the user when he create new post .. it is saved directly to tutorial category .. and if user was in list template (let's say news) .. he will create new post which will be saved directly to news category.
i mean create new post saved directly to current category.
i believe i will use (pass url parameter to class based views) but actually i failed to do that .. and i searched tonnage of questions without got what i want.
can any body help .. with sample please.
models.py
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
def save(self, *args, **kwargs):
if not self.slug and self.name:
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
def PostListView(request, category_slug=None):
category = None
posts = Post.objects.all().prefetch_related().annotate(commentscountperpost=Count('comments'))
categories = Category.objects.prefetch_related().annotate(total_product_category=Count('post'))
if category_slug:
category = Category.objects.get(slug=category_slug)
posts = posts.filter(category=category)
context = {
'title': 'Home Page',
'posts': posts,
'total_posts': total_posts,
'categories': categories,
'category': category,}
return render(request, 'blog/index.html', context)
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
template_name = 'blog/new_post.html'
form_class = PostCreateForm
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
forms.py
class PostCreateForm(forms.ModelForm):
title = forms.CharField(label='Title')
content = forms.CharField(label='Content', widget=forms.Textarea)
class Meta:
model = Post
fields = ['title', 'content']
urls.py
path('index_list/', PostListView, name='list'),
path('<slug:category_slug>', PostListView, name='post_category_list'),
path('new_post/', PostCreateView.as_view(), name='new_post'),
new_post.html template
{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
<div class="border p-4 mb-5">
<legend class="border-bottom pb-1 mb-3">New Post </legend>
<form method="POST">
{% csrf_token %}
{{form|crispy}}
<input class="btn btn-secondary mt-4" type="submit" value="Add New Post">
</form>
</div>
{% endblock content %}
list.html template
{% for category in categories %}
<h5><a class="text-primary" href="{% url 'post_category_list' category.slug %}">
{{ category.name }} ({{ category.total_product_category }})</a></h5>
{% endfor %}
<h5>{{ total_posts }} Total Posts </h5>
{% if category %}
New {{ category }}
{% endif %}
You can try like this:
class PostCreateView(generic.CreateView):
model = Post
template_name = 'blog/new_post.html'
form_class = CreatePostForm
slug_url_kwarg = 'slug'
def form_valid(self, form):
category = Category.objects.get(slug=self.kwargs['slug'])
form.instance.category = category
form.instance.author = self.request.user
return super(PostCreateView, self).form_valid(form)
And in the urls
path('new_post/<slug>/', PostCreateView.as_view(), name='new_post'),
yes i found it , depending on arjun answer, greate thanks for arjun
in list posts per category template change :
New {{ category }}
to:
New {{ category }}
and it works fine,
thanks.
I want make blog where I have categories and posts inside.
Categories should be displayed, and when you click on it, you are redirected to another site where articles of this category are shown.
models.py:
class Category(CMSPlugin):
title = models.CharField(max_length=20, default='category')
def __unicode__(self):
return self.title
class Blog_post(CMSPlugin):
category = models.ForeignKey(Category)
style = models.ForeignKey(Blog_style)
title = models.CharField(max_length=200, default='title')
description = models.CharField(max_length=200,default='description')
image = models.ImageField(upload_to='static', null=True, blank=True)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __unicode__(self):
return self.title
views.py
def Blog_list(request):
posts = Blog_post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
category = Category.objects.all()
return render(request, 'blogspot.html', {'posts': posts, 'category':category})
def post_detail(request, pk):
post = get_object_or_404(Blog_post, pk=pk)
return render(request, 'post_detail.html', {'post': post})
def category_detail(request, pk):
cat = get_object_or_404(Category, id=pk)
post_with_category = Blog_post.objects.filter(category=cat)
return render(request, 'articles.html', {'post_with_category': post_with_category})
blogspot.html
{% for post in posts %}
<h1>{{post.title}}</h1>
<a href="{% url 'category_detail' pk=post.category.id %}" >{{ post.category }}</a>
{{post.title}}
{{ post.description }}
{{ post.image }}
{{ post.text }}{{ post.published_date }}
{% endfor %}
So far works all ok. I can click on {{post.title}} and im redirected to post_detail. Now i want to make same logic with categories. When i click on {{post.category}} i want redirect to articles.html where u can see all articles in specific category.
EDIT:
I inserted code to show posts in categories. I stucked with for loop. If i use loop mentioned in post, I get all posts and categories. The problem is if i have 2 posts in one category and this loop will show 2x "category" in template.
So I edited my for loop.
{% for post in category %}
{{post.title}}
{% endfor %}
If I insert <a href="{% url 'category_detail' pk=post.category.id %}" >{{post.title}} in this loop i get no reverse match.
I tried to modify views.py category_detail
And url should looks like localhost/<category>/
And another question is, what is QRM alternative comand for "select*from Table Where Column_id= id ;
urls.py
url(r'^blog/$', views.Blog_list, name='Blog_list'),
url(r'^blog/(?P<pk>\d+)/$', views.post_detail, name='post_detail'),
If I understand your question, django allows you to reference FK objects through the main object. So, since your post.category is an instance of your Category model, you should be able to use post.category.id to do a reverse lookup, so your template would have something along the lines of:
<a href="{% url 'category_detail' pk=post.category.id %}" >{{ post.category }}</a>
Then, in your category_detail view you would just use the pk to get the lookup:
cat = get_object_or_404(Category, id=pk)
post_with_category = Blog_post.objects.filter(category=cat)
Then you could display the list of posts on the new url link that have the same category, via your new post_with_category object list.
EDIT:
Your urls would want to include something like the following for the above html href tag to work:
url(r'^cat/(?P<pk>[0-9]+)/$', views.category_detail, name='category_detail'),
I broke something. The error reads: Reverse for 'wiki_article_detail' with arguments '(u'',)' and keyword arguments '{}' not found. I don't know where the 'u' came from in arguments. here is the model:
class Article(models.Model):
"""Represents a wiki article"""
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=50, unique=True)
text = models.TextField()
author = models.ForeignKey(User)
is_published = models.BooleanField(default=False, verbose_name="Publish?")
created_on = models.DateTimeField(auto_now_add=True)
objects = models.Manager()
published = PublishedArticlesManager()
country = models.CharField(max_length=100)
category = models.CharField(max_length=100)
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Article, self).save(*args, **kwargs)
#models.permalink
def get_absolute_url(self):
return ('wiki_article_detail', (), { 'slug': self.slug })
The template is:
<body>
{% if object_list %}
<h2 class="articlePageTitle">All Articles</h2>
<h3>Filter by country</h3>
<h3>Filter by category</h3>
<ul>
{% for article in object_list %}
<li>
{{ article.title }}
</li>
{% endfor %}
</ul>
{% else %}
<h2>No articles have been published yet.</h2>
{% endif %}
<a href="{% url wiki_article_add %}">Create new article</a
</body>
the debugger is indicating the error in this line:
{{ article.title }}
This was all working fine before, I had some db problems and had to recreate the db file, but there wasn't much in there. But now, I can write an article and view it, but I can't get to the /all list.
urls.py snippet:
url(r'^all/$',
'django.views.generic.list_detail.object_list',
{
'queryset': Article.published.all(),
},
name='wiki_article_index'),
the urls.py snippet that is referenced in the error:
url(r'^article/(?P<slug>[-\w]+)$',
'django.views.generic.list_detail.object_detail',
{
'queryset': Article.objects.all(),
},
name='wiki_article_detail'),
Try this one:
{{ article.title }}
I have a blog app with a list of the latest post titles. Now the list item should be linked to its content. My problem (similar post) is that if the title has some spaces i get a url with spaces if i use:
<a href="{{ i.id }}/{{ i.title }}">{{ i.title }}
in my template. I could use an additional URLField but i dont want to create the url-friendly title manually. What's the common way to do this?
My models.py
class Post(models.Model):
title = models.CharField(max_length=100)
...
def __unicode__(self):
return self.title
My view.py
def recentlyBlogged(request):
lastPosts = Post.objects.filter(publication__gt = datetime.now() - timedelta(days=30))
return render(request, "blog/blog.html", {'Posts': lastPosts})
My template
{% for i in Posts %}
<ul id="latestPostsList">
<li class="latestPostsListItem">{{ i }}</li>
{% endfor %}
</ul>
You are looking for a slug.
Try this
from django.template.defaultfilters import slugify
class Post(models.Model):
title = models.CharField(max_length=100)
...
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse('post_url', args=(slugify(self.title), ))
and in the template,
{{ i.title }}
You might have to modify urls.py accordingly too
url(r'post_url/(?P<slug>[\w-]+)/', view_name, name="post_url")