上一篇‘博客系统’的博客还没有实现评论,按标签搜索、按日期搜索、按分类搜索的功能,这篇博客主要是对以上功能的增加。
增添评论
第一步:新建app:comment,在主setting.py中添加新app,修改主urls.py文件
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'',include('blog.urls')),
url(r'',include('comments.urls')),
]
第二步:编写评论的数据库表单
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
from blog.models import Post
class Comment(models.Model):
user =models.ForeignKey(User,verbose_name='用户')
email = models.EmailField(verbose_name='电子邮箱')
text = models.TextField(max_length=255,verbose_name='评论正文')
# auto_now_add=True 自动create_time为最新一次更改评论信息的时间
create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
post = models.ForeignKey(Post)
class Meta:
verbose_name = '评论'
verbose_name_plural = '评论'
def __str__(self):
return self.text[:4]
第三步:编写评论的路由comment.urls.py和comment.views.py
# comment.views.py
from django.shortcuts import render, get_object_or_404,redirect
# Create your views here.
from blog.models import Post
from comments.forms import CommentForm
def post_comment(request, id):
# 1. 获取用户选择的博客
post = get_object_or_404(Post, id=id)
# 2. 如果用户提交评论
if request.method == 'POST':
print(request.POST)
form = CommentForm(request.POST)
# 2.1 判断表单是否合法
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
# 2.2 如果不合法,则提交错误信息
else:
return render(request, 'blog/detail.html',
context={
'errors': form.errors
})
# 3. 如果不是POST请求,访问用户详情页
return redirect(post.get_url())
# comment.urls
from django.conf.urls import url, include
from django.contrib import admin
from comments import views
app_name = 'comment'
urlpatterns = [
url(r'^comment/blog/(?P<id>\d+)/$',views.post_comment,name='post_comment'),
]
第四步:编写评论表单
# 同步与数据库评论的形式
from comments.models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['user','email','text']
第五步:修改HTML文件中关于评论的部分
<section class="comment-area" id="comment-area">
<hr>
<h3>发表评论</h3>
<form action="{% url 'comment:post_comment' post.id %}" method="post" class="comment-form">
{% csrf_token %}
<div class="row">
<div class="col-md-4">
<label for="{{ form.user.id }}">{{ form.user.label }}</label>
{{ form.user }}
</div>
<div class="col-md-4">
<label for="{{ form.email.id }}">{{ form.email.label }}</label>
{{ form.email }}
</div>
<div class="col-md-12">
<label for="{{ form.text.id }}">{{ form.text.label }}</label>
{{ form.text }}
<button type="submit" class="comment-btn">发表</button>
</div>
</div> <!-- row -->
</form>
<div class="comment-list-panel">
<h3>评论列表,共 <span>{{ comments.count }}</span> 条评论</h3>
<ul class="comment-list list-unstyled">
{% for comment in comments %}
<li class="comment-item">
<span class="nickname">{{ comment.user }}</span>
<time class="submit-date"
datetime="{{ comment.create_time }}">{{ comment.create_time }}</time>
<div class="text">
{{ comment.text }}
</div>
</li>
{% endfor %}
</ul>
</div>
</section>
自定义标签
实现按标签搜索、按日期搜索、按分类搜索的功能
第一步:自定义标签
- 准备(必需)工作:
在某个app下创建一个名为templatetags(必需,且包名不可变)的包。假设我们在名为blog的app下创建了一个templatetags的包,并在该包下创建了一个名为blog_tags的文件.
确保settings文件中的INSTALLD_APPS内必须含有该app
修改setting.py有关时间显示的部分
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
#如果setting中配置USE_TZ=True则输出的是UTC时间(naive time),
# 如果setting中配置USE_TZ=False,则该输出时间与datetime.datetime.now()完全相同
# USE_TZ = True
USE_TZ = False
2. 接下来在blog_tags文件中写入如下几行
from django import template
register = template.Library()
3. 在模板中使用{% load %} 标签装载自定义标签或者装饰器
from django import template
from django.db.models import Count
from blog.models import Post, Category, Tag
register = template.Library()
@register.simple_tag
def get_recent_posts(num=3):
return Post.objects.all().order_by('-create_time')[:num]
@register.simple_tag
def archives():
return Post.objects.dates(field_name='create_time',
kind='month',
order='DESC')
@register.simple_tag
def get_category():
return Category.objects.annotate(num_posts=Count('post')).filter(num_posts__gt=0)
@register.simple_tag
def get_tags():
# return Tag.objects.all()
return Tag.objects.annotate(num_posts = Count('post'))
第二步: 编写标签查找的路由和视图函数
路由
#blog.urls.py
from django.conf.urls import url
from django.contrib import admin
from blog import views
app_name = 'blog'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'blog/(?P<id>\d+)/$', views.detail, name='detail'),
url(r'^archive/(?P<year>\d{4})/(?P<month>\d{1,2})/', views.archive, name='archive'),
url(r'^category/(?P<id>\d+)/', views.category, name='category'),
url(r'^tag/(?P<id>\d+)/', views.tag, name='tag'),
url(r'^search', views.search, name='search')
]
视图函数
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
# Create your views here.
from markdown import markdown
from blog.models import Post, Tag
from comments.forms import CommentForm
def index(request):
# return HttpResponse('ok index!')
posts = Post.objects.all()
return render(request,'blog/index.html',context={
'posts':posts
})
def detail(request,id):
# return HttpResponse('ok,%s detail' %(id))
post = Post.objects.get(id=id)
post.add_views()
form = CommentForm()
comments = post.comment_set.all()
post.body = markdown(post.body,
extensions=['markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc', ],
output_format='html')
return render(request,'blog/detail.html',context={
'post':post,
'comments':comments,
'form':form,
})
def archive(request,year,month):
posts = Post.objects.filter(
create_time__year=year,
create_time__month=month
).order_by('-create_time')
return render(request,'blog/index.html',context={
'posts':posts
})
def category(request,id):
posts = Post.objects.filter(category_id=id)
return render(request,'blog/index.html',
context={
'posts':posts
})
def tag(request,id):
tag = get_object_or_404(Tag,id=id)
posts = Post.objects.filter(tags=tag).order_by('-create_time')
return render(
request, 'blog/index.html',
context={
'posts': posts
}
)
def search(request):
query = request.GET.get('query',None)
posts = Post.objects.filter(
Q(title__icontains=query) |
Q(body__icontains=query)
)
if not posts:
return render(request,'blog/index.html',
context={
'posts':posts,
'message':'没有找到相关信息'
}
)
else:
return render(request, 'blog/index.html',
context={
'posts': posts
}
)
第三步:修改Html文件,仅截取部分代码
这里在博客详情页需要显示的是博客的结构(目录),添加显示目录的代码
修改视图函数
def detail(request,id):
# return HttpResponse('ok,%s detail' %(id))
post = Post.objects.get(id=id)
post.add_views()
form = CommentForm()
comments = post.comment_set.all()
# post.body = markdown(post.body,
# extensions=['markdown.extensions.extra',
# 'markdown.extensions.codehilite',
# 'markdown.extensions.toc', ],
# output_format='html')
md = Markdown(
extensions=['markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc', ],
output_format='html'
)
# Convert markdown to serialized XHTML or HTML.
post.body = md.convert(post.body)
post.toc = md.toc
return render(request,'blog/detail.html',context={
'post':post,
'comments':comments,
'form':form,
})
右侧导航栏
{# 基模板 #}
<aside class="col-md-4">
{% block toc %}
{% endblock %}
<div class="widget widget-recent-posts">
<h3 class="widget-title">最新文章</h3>
<ul>
{% get_recent_posts as recent_posts %}
{% for post in recent_posts %}
<li>
<a href="{{ post.get_url }}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</div>
<div class="widget widget-archives">
<h3 class="widget-title">归档</h3>
<ul>
{% archives as dates %}
{% for date in dates %}
<li>
<a href="{% url 'blog:archive' date.year date.month %}">{{ date.year }}年 {{ date.month }}月</a>
</li>
{% endfor %}
</ul>
</div>
<div class="widget widget-category">
<h3 class="widget-title">分类</h3>
<ul>
{% get_category as categories %}
{% for category in categories %}
<li>
<a href="{% url 'blog:category' category.id %}">{{ category.name }}<span
class="post-count">({{ category.num_posts }})</span></a>
</li>
{% endfor %}
</ul>
</div>
<div class="widget widget-tag-cloud">
<h3 class="widget-title">标签云</h3>
<ul>
{% get_tags as tags %}
{% for tag in tags %}
<li>
<a href="{% url 'blog:tag' tag.id %}">{{ tag.name }}</a>
</li>
{% endfor %}
</ul>
</div>
详情页添加博客目录
{# blog/detail.html #}
{% block toc %}
<div><h3 class="widget-title">文章目录</h3>
{{ post.toc | safe }}
</div>
{% endblock %}
按类别查找
按标签查找
按时间查找
显示博客目录
分页
Django提供了一个新的类来帮助你管理分页数据,这个类存放在django/core/paginator.py.它可以接收列表、元组或其它可迭代的对象。
def index(request):
all_posts = Post.objects.count()
if all_posts % PER_PAGE != 0:
page_nums = all_posts // PER_PAGE + 1
else:
page_nums = all_posts // PER_PAGE
paginator = Paginator(Post.objects.all(),PER_PAGE)
if request.GET.get('page'):
page = request.GET.get('page')
else:
page = 1
try:
posts = paginator.page(page)
except (PageNotAnInteger,EmptyPage):
posts = paginator.page(1)
posts.has_previous()
posts.has_next()
posts.previous_page_number()
posts.next_page_number()
return render(request, 'blog/index.html',
context={
'title':'博客首页',
'posts':posts,
'pages_num':page_nums,
})
修改主页的html文件有关分页显示的部分
<div class="pager">
{% if posts.has_previous %}
<a href="?page={{ posts.previous_page_number }}">上一页</a>
{% else %}
<a href="#">上一页</a>
{% endif %}
<span class="current">第 {{ posts.number }} 页 / 共 {{ pages_num }} 页</span>
{% if posts.has_next %}
<a href="?page={{ posts.next_page_number }}">下一页</a>
{% else %}
<a href="#">下一页</a>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。