I developed a django blog application using djangogirls.com tutorial. I am trying to add a blog category but I just can't do it!
I was searching google and stackoverflow.com like crazy , but , being a newbie in python/django I couldn't successfully add categories to my blog.
My models:
from django.db import models
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey('auth.User')
title = models.CharField(max_length=200)
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 __str__(self):
return self.title
My views:
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from .models import Post
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
My urls:
from django.conf.urls import include, url
from . import views
urlpatterns = [
url(r'^$', views.post_list, name='post_list'),
url(r'^post/(?P<pk>\d+)/$', views.post_detail, name='post_detail'),
]
My post_list.html: {% extends 'blog/base.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
<div class="date">
{{ post.published_date }}
</div>
<h1><a href="{% url 'post_detail' pk=post.pk %}">{{post.title }}</a></h1>
<p>{{ post.text|truncatewords:100}}</p>
</div>
{% endfor %}
{% endblock %}
My post_detail.html:
{% extends 'blog/base.html' %}
{% block content %}
<div class="post">
{% if post.published_date %}
<div class="date">
{{ post.published_date }}
</div>
{% endif %}
<h1>{{ post.title }}</h1>
<p>{{ post.text|linebreaks }}</p>
</div>
{% endblock %}
Ok. If somebody can help me out , I need to create a category model for this blog model ,I would really appreciate it ! Thanks in advance!
I'd go with
class Category(models.Model):
title = models.CharField(max_length=255, verbose_name="Title")
...
class Post(models.Model):
category = models.ForeignKey(Category, verbose_name="Category")
title = models.CharField(max_length=255, verbose_name="Title")
text = models.TextField()
...
When you have a post like this:
post = Post.objects.first()
you can access it's category's title with post.category.title
or when you have a category like this:
category = Category.objects.first()
you can get the posts under that category with category.post_set.all()
.
I have edited your code to show how I'd write if that was a project I am working on. Here it is:
models.py
from django.db import models
from django.utils import timezone
class Category(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
title = models.CharField(max_length=255, verbose_name="Title")
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
ordering = ['title']
def __str__(self):
return self.title
class Post(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
is_published = models.BooleanField(default=False, verbose_name="Is published?")
published_at = models.DateTimeField(null=True, blank=True, editable=False, verbose_name="Published at")
category = models.ForeignKey(Category, verbose_name="Category")
author = models.ForeignKey('auth.User', verbose_name="Author")
title = models.CharField(max_length=200, verbose_name="Title")
text = models.TextField(verbose_name="Text")
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['-created_at']
def publish(self):
self.is_published = True
self.published_at = timezone.now()
self.save()
def __str__(self):
return self.title
views.py
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from .models import Category, Post
def category_list(request):
categories = Category.objects.all() # this will get all categories, you can do some filtering if you need (e.g. excluding categories without posts in it)
return render (request, 'blog/category_list.html', {'categories': categories}) # blog/category_list.html should be the template that categories are listed.
def category_detail(request, pk):
category = get_object_or_404(Category, pk=pk)
return render(request, 'blog/category_detail.html', {'category': category}) # in this template, you will have access to category and posts under that category by (category.post_set).
def post_list(request):
posts = Post.objects.filter(published_at__lte=timezone.now()).order_by('published_at')
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
urls.py
from django.conf.urls import include, url
from . import views
urlpatterns = [
url(r'^category$', views.category_list, name='category_list'),
url(r'^category/(?P<pk>\d+)/$', views.category_detail, name='category_detail'),
url(r'^$', views.post_list, name='post_list'),
url(r'^post/(?P<pk>\d+)/$', views.post_detail, name='post_detail'),
]
I didn't write templates, they are up to you.