一、项目概述
项目运行环境
- Python3.6+
- Django 1.11
- MySQL 5.7
- 其他插件(图片处理、分页、验证码....)
项目详细功能介绍
前台功能
-
项目首页展示
-
轮播图
-
博客推荐
-
最新发布
-
博客分类
-
最新评论文章
-
widgets小插件
-
搜索功能
-
博客分类功能
-
博客标签查询
-
友情链接
-
博客分页功能
-
博客详细
-
最新评论文章
-
发表评论
-
评论展示
-
评论数
-
阅读数
-
登录功能
-
注册功能
-
邮箱验证功能
-
注销功能
-
页面模板
-
标签云功能
-
读者墙功能
后台功能
-
用户维护
-
权限管理
-
博客分类维护
-
标签维护
-
友情链接
-
轮播图维护
项目演示
项目演示
项目代码演示
代码展示
二、开发环境搭建
使用virtualenv 和 virtualenwrapper
1. MySQL 5.7
sudo apt install mysql-server mysql-client
2. 安装mysql驱动
pip install pymysql
3. 安装Django
pip install django==1.11
三、创建项目
创建项目和应用
- 创建项目
django-admin startproject django-blog
- 创建应用
python manage.py startapp userapp
python manage.py startapp blogapp
配置数据库
- 在settings中配置数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_blog_db',
'USER': 'root',
'PASSWORD': 'wwy123',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
创建数据库(执行迁移文件)
python manage.py migrate
创建超级管理员
python manage.py createsuperuser
四、创建数据模型
USERAPP
USER(用户模型)
from django.contrib.auth.models import AbstractUser
class BlogUser(AbstractUser):`
nikename = models.CharField('昵称', max_length=20, default='')
提示:需要在settings配置文件中设置:AUTH_USER_MODEL = 'users.BlogUser'
EMAIL(邮箱验证数据模型)
class EmailVerifyRecord(models.Model):`
code = models.CharField(verbose_name='验证码', max_length=50,default='')
email = models.EmailField(max_length=50, verbose_name="邮箱")
send_type = models.CharField(verbose_name="验证码类型", choices=(("register",u"注册"),("forget","找回密码"), ("update_email","修改邮箱")), max_length=30)
send_time = models.DateTimeField(verbose_name="发送时间", default=datetime.now)
class Meta:
verbose_name = "邮箱验证码"
复数
verbose_name_plural = verbose_name
def __str__(self):
return '{0}({1})'.format(self.code, self.email)
BLOGAPP
Banner(轮播图模型)
class Banner(models.Model):`
title = models.CharField('标题', max_length=50)
cover = models.ImageField('轮播图', upload_to='static/images/banner')
link_url = models.URLField('图片链接', max_length=100)
idx = models.IntegerField('索引')
is_active = models.BooleanField('是否是active', default=False)
def __str__(self):
return self.title
class Meta:
verbose_name = '轮播图'
verbose_name_plural = '轮播图'
Category(博客分类模型)
class BlogCategory(models.Model):`
name = models.CharField('分类名称', max_length=20, default='')
class Meta:
verbose_name = '博客分类'
verbose_name_plural = '博客分类'
def __str__(self):
return self.name
Tags(标签模型)
class Tags(models.Model):`
name = models.CharField('标签名称', max_length=20, default='')
class Meta:
verbose_name = '标签'
verbose_name_plural = '标签'
def __str__(self):
return self.name
Blog(博客模型)
class Post(models.Model):`
user = models.ForeignKey(BlogUser, verbose_name='作者')
category = models.ForeignKey(BlogCategory, verbose_name='博客分类', default=None)
tags = models.ManyToManyField(Tags, verbose_name='标签')
title = models.CharField('标题', max_length=50)
content = models.TextField('内容')
pub_date = models.DateTimeField('发布日期', default=datetime.now)
cover = models.ImageField('博客封面', upload_to='static/images/post', default=None)
views = models.IntegerField('浏览数', default=0)
recommend = models.BooleanField('推荐博客', default=False)
def __str__(self):
return self.title
class Meta:
verbose_name = '博客'
verbose_name_plural = '博客'
Comment(评论模型)
class Comment(models.Model):`
post = models.ForeignKey(Post, verbose_name='博客')
user = models.ForeignKey(BlogUser, verbose_name='作者')
pub_date = models.DateTimeField('发布时间')
content = models.TextField('内容')
def __str__(self):
return self.content
class Meta:
verbose_name = '评论'
verbose_name_plural = '评论'
FriendlyLink(友情链接模型)
class FriendlyLink(models.Model):`
title = models.CharField('标题', max_length=50)
link = models.URLField('链接', max_length=50, default='')
def __str__(self):
return self.title
class Meta:
verbose_name = '友情链接'
verbose_name_plural = '友情链接'
五、实现首页页面模板
创建模板文件夹
创建模板文件templates,并在settings.py中设置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
配置静态文件路径
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
六、创建首页路由
- 创建视图函数
def index(request):`
return render(request, 'index.html', {})
- 配置url
url(r'^$', index, name='index' )
- 修改模板CSS JS等静态文件的路径
七、实现幻灯片功能(Banner)
- 注册模型
from blogs.models import Banner
admin.site.register(Banner)
- 编写views
from .models import Banner
`def index(request):`
banner_list = Banner.objects.all()
ctx = {
'banner_list': banner_list,
}
return render(request, 'index.html', ctx)
- 模板
<!-- banner 开始 -->
<div id="focusslide" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
`{% for banner in banner_list %}`
`{% if banner.is_active %}`
` <li data-target="#focusslide" data-slide-to="{{banner.idx}}" class="active"></li>`
`{% else %}`
` <li data-target="#focusslide" data-slide-to="{{banner.idx}}"></li>`
`{% endif %}`
`{% endfor %}`
` </ol>`
` <div class="carousel-inner" role="listbox">`
`{% for banner in banner_list %}`
`{% if banner.is_active %}`
`<div class="item active">`
`<a href="{{banner.link_url}}" target="_blank" title="{{banner.title}}" >`
`<img src="{{banner.cover}}" alt="{{banner.title}}" class="img-responsive"></a>`
`</div>`
`{% else %}`
`<div class="item">`
`<a href="{{banner.link_url}}" target="_blank" title="{{banner.title}}" >`
`<img src="{{banner.cover}}" alt="{{banner.title}}" class="img-responsive"></a>`
`</div>`
`{% endif %}`
`{% endfor %}`
` </div>`
` <a class="left carousel-control" href="#focusslide" role="button" data-slide="prev" rel="nofollow">`
`<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>`
`<span class="sr-only">上一个</span> </a>`
`<a class="right carousel-control" href="#focusslide" role="button" data-slide="next" rel="nofollow">`
`<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>`
`<span class="sr-only">下一个</span> </a>`
`</div>`
`<!-- banner 结束 -->`
八、实现博客推荐
- 注册模型
from blogs.models import Banner,Post,BlogCategory,Tags
...
admin.site.register(BlogCategory)
admin.site.register(Tags)
admin.site.register(Post)
- 编写views
# 视图函数 HTTPRequest
`def index(request):`
banner_list = Banner.objects.all()
recommend_list = Post.objects.filter(recommend=1)
ctx = {
'banner_list': banner_list,
'recommend_list': recommend_list,
}
return render(request, 'index.html', ctx)
- 模板
<!-- 推荐开始 -->
{% for post in recommend_list %}
<article class="excerpt-minic excerpt-minic-index">
<h2><span class="red">【推荐】</span><a target="_blank" href="/blog/{{post.id}}/" title="{{post.title}}" >{{post.title}}</a>
</h2>
<p class="note">{{post.content}}</p>
</article>
{% endfor %}
<!-- 推荐结束 -->
九、实现最新发布
- 编写views
# 视图函数 HTTPRequest
`def index(request):`
...
post_list = Post.objects.order_by('-pub_date').all()[:10]
....
ctx = {
'banner_list': banner_list,
'recommend_list': recommend_list,
'post_list': post_list,
}
return render(request, 'index.html', ctx)
- 模板
<!-- 最新发布的博客开始 -->
{% for post in post_list%}
<article class="excerpt excerpt-1" style="">
<a class="focus" href="/blog/{{post.id}}/" title="{{post.title}}" target="_blank" ><img class="thumb" data-original="/{{post.cover}}" src="/{{post.cover}}" alt="{{post.title}}" style="display: inline;"></a>
<header><a class="cat" href="#" title="{{post.category.name}}" >{{post.category.name}}<i></i></a>
<h2><a href="/blog/{{post.id}}/" title="{{post.title}}" target="_blank" >{{post.title}}</a>
</h2>
</header>
<p class="meta">
<time class="time"><i class="glyphicon glyphicon-time"></i>{{post.pub_date|date:'Y-m-d'}}</time>
<span class="views"><i class="glyphicon glyphicon-eye-open"></i>{{post.views}}</span> <a class="comment" href="##comment" title="评论" target="_blank" ><i class="glyphicon glyphicon-comment"></i>{{post.comment_set.count}}</a>
` </p>`
` <p class="note">`
`{% autoescape off %}`
{{post.content | truncatechars_html:200}}
{% endautoescape %}
</p>
</article>
{% endfor %}
<!-- 最新发布的博客结束 -->
十、实现博客分类功能
- 编写视图
# 视图函数 HTTPRequest
`def index(request):`
banner_list = Banner.objects.all()
recommend_list = Post.objects.filter(recommend=1)
post_list = Post.objects.order_by('-pub_date').all()[:10]
blogcategory_list = BlogCategory.objects.all()
ctx = {
'banner_list': banner_list,
'recommend_list': recommend_list,
'post_list': post_list,
'blogcategory_list': blogcategory_list,
}
return render(request, 'index.html', ctx)
- 模型
<div class="title">
<h3>最新发布</h3>
<div class="more">
{%for c in blogcategory_list%}
<a href="/category/{{c.id}}" title="{{c.name}}" >{{c.name}}</a>
{% endfor %}
</div>
</div>
十一、实现最新评论功能
- 编写views
<ul>
{% for post in new_comment_list %}
<li><a title="{{ post.title }}" href="#"><span class="thumbnail">
` <img class="thumb" data-original="/{{ post.cover }}"`
`src="/{{ post.cover }}"`
alt="{{ post.title }}" style="display: block;">
</span><span class="text">{{ post.title }}</span><span class="muted"><i
class="glyphicon glyphicon-time"></i>
` {{ post.pub_date }}`
</span><span class="muted"><i class="glyphicon glyphicon-eye-open"></i>{{ post.views }}</span></a></li>
`{% endfor %}`
`</ul>`
十二、实现搜索功能
- 编写views
from django.views.generic.base import View
from django.db.models import Q
`class SearchView(View):`
# def get(self, request):
# pass
def post(self, request):
kw = request.POST.get('keyword')
post_list = Post.objects.filter(Q(title__icontains=kw)|Q(content__icontains=kw))
ctx = {
'post_list': post_list
}
return render(request, 'list.html', ctx)
* urls
url(r'^search$', SearchView.as_view(), name='search'),
十三、实现友情链接
- 编写视图 (数据源)
`def index(request):`
....
friendlylink_list = FriendlyLink.objects.all()
.....
- 模板
<div class="widget widget_sentence">
`<h3>友情链接</h3>`
`<div class="widget-sentence-link">`
`{% for friendlylink in friendlylink_list %}`
`<a href="{{ friendlylink.link }}" title="{{ friendlylink.title }}"`
`target="_blank">{{ friendlylink.title }}</a> `
`{% endfor %}`
`</div>`
`</div>`
十四、实现博客列表功能
- 编写views
`def blog_list(request):`
post_list = POST.objects.all()
ctx = {
'post_list': post_list,
}
return render(request, 'list.html', ctx)
- 编写路由
url(r'^list$', blog_list, name='blog_list'),
* base.html
`<!doctype html>`
`<html lang="zh-CN">`
`<head>`
`<meta charset="utf-8">`
`<meta name="renderer" content="webkit">`
`<meta http-equiv="X-UA-Compatible" content="IE=edge">`
`<meta name="viewport" content="width=device-width, initial-scale=1">`
<title>{% block title %}知奇博客首页 {% endblock %}</title>
`<meta name="keywords" content="">`
`<meta name="description" content="">`
{% block custom_css %}{% endblock %}
`<link rel="stylesheet" type="text/css" href="/static/css/bootstrap.min.css">`
`<link rel="stylesheet" type="text/css" href="/static/css/nprogress.css">`
`<link rel="stylesheet" type="text/css" href="/static/css/style.css">`
`<link rel="stylesheet" type="text/css" href="/static/css/font-awesome.min.css">`
`<link rel="apple-touch-icon-precomposed" href="/static/images/icon.png">`
`<link rel="shortcut icon" href="/static/images/favicon.ico">`
`<script src="/static/js/jquery-2.1.4.min.js"></script>`
`<script src="/static/js/nprogress.js"></script>`
`<script src="/static/js/jquery.lazyload.min.js"></script>`
`</head>`
`<body class="user-select">`
`<header class="header">`
`<nav class="navbar navbar-default" id="navbar">`
`<div class="container">`
<div class="header-topbar hidden-xs link-border">
<ul class="site-nav topmenu">
<li><a href="#" >标签云</a></li>
<li><a href="#" rel="nofollow" >读者墙</a></li>
<li><a href="#" title="RSS订阅" >
<i class="fa fa-rss">
</i> RSS订阅
</a></li>
</ul>
爱学习 更爱分享
</div>
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#header-navbar" aria-expanded="false"> <span class="sr-only"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button>
<h1 class="logo hvr-bounce-in"><a href="#" title="知奇课堂博客"><img src="/static/images/201610171329086541.png" alt="知奇课堂博客"></a></h1>
</div>
<div class="collapse navbar-collapse" id="header-navbar">
<ul class="nav navbar-nav navbar-left">
<li><a data-cont="知奇课堂博客" title="知奇课堂博客" href="/">首页</a></li>
<li><a data-cont="博客" title="博客" href="/list">博客</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
{% if user.is_authenticated %}
<li><a data-cont="用户" title="用户" href="#">欢迎,{{user.username}}</a></li>
<li><a data-cont="注册" title="注册" href="/logout">注销</a></li>
{% else %}
<li><a data-cont="登录" title="登录" href="/login">登录</a></li>
<li><a data-cont="注册" title="注册" href="/register">注册</a></li>
{% endif %}
</ul>
</div>
`</div>`
`</nav>`
`</header>`
{% block content %}
{% endblock %}
`<footer class="footer">`
`<div class="container">`
<p>Copyright © 2016.Company name All rights reserved.</p>
`</div>`
`<div id="gotop"><a class="gotop"></a></div>`
`</footer>`
`<script src="/static/js/bootstrap.min.js"></script>`
`<!-- <script src="/static/js/jquery.ias.js"></script> -->`
`<script src="/static/js/scripts.js"></script>`
`</body>`
`</html>`
十五、实现分页功能
- 安装包
pip install django-pure-pagination
参考链接: https://github.com/jamespacileo/django-pure-pagination
`def blog_list(request):`
post_list = Post.objects.all()
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
p = Paginator(post_list, per_page=1, request=request)
post_list = p.page(page)
ctx = {
'post_list': post_list,
}
return render(request, 'list.html', ctx)
- 模板
<section class="container">
`<div class="content-wrap">`
`<div class="content">`
`<div class="title">`
<h3 style="line-height: 1.3">博客列表</h3>
`</div>`
`{% for post in post_list.object_list %}`
<article class="excerpt excerpt-1"><a class="focus" href="/blog/{{post.id}}" title="{{post.title}}" target="_blank" >
<img class="thumb" data-original="/{{post.cover}}" src="/{{post.cover}}" alt="{{post.title}}" style="display: inline;"></a>
<header><a class="cat" href="/category/{{post.category.id}}" title="{{post.category.name}}" >{{post.category.name}}<i></i></a>
<h2><a href="/blog/{{post.id}}" title="{{post.title}}" target="_blank" >{{post.title}}</a></h2>
` </header>`
<p class="meta">
<time class="time"><i class="glyphicon glyphicon-time"></i> {{post.pub_date|date:'Y-m-d'}}</time>
<span class="views"><i class="glyphicon glyphicon-eye-open"></i> {{post.views}}</span>
<a class="comment" href="##comment" title="评论" target="_blank" ><i class="glyphicon glyphicon-comment"></i>{{post.comment_set.count}}</a></p>
<p class="note">{{post.content}}</p>
`</article>`
`{% endfor %}`
`{% include "_pagination.html" %}`
* _pagination.html
{% load i18n %}
<div class="pagination">
`{% if post_list.has_previous %}`
`<a href="?{{ post_list.previous_page_number.querystring }}" class="prev">‹‹ 上一页</a>`
`{% else %}`
`<span class="disabled prev">‹‹ 上一页</span>`
`{% endif %}`
`{% for page in post_list.pages %}`
`{% if page %}`
`{% ifequal page post_list.number %}`
`<span class="current page">{{ page }}</span>`
`{% else %}`
`<a href="?{{ page.querystring }}" class="page">{{ page }}</a>`
`{% endifequal %}`
`{% else %}`
`...`
`{% endif %}`
`{% endfor %}`
`{% if post_list.has_next %}`
`<a href="?{{ post_list.next_page_number.querystring }}" class="next">下一页 ››</a>`
`{% else %}`
`<span class="disabled next">下一页 ››</span>`
`{% endif %}`
`</div>`
十六、实现标签云功能
`class TagMessage(object):`
def __init__(self, tid, name, count):
self.tid = tid
self.name = name
self.count = count
`def blog_list(request):`
post_list = Post.objects.all()
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
p = Paginator(post_list, per_page=1, request=request)
post_list = p.page(page)
tags = Tags.objects.all()
tag_message_list = []
for t in tags:
count = len(t.post_set.all())
tm = TagMessage(t.id, t.name, count)
tag_message_list.append(tm)
ctx = {
'post_list': post_list,
'tags': tag_message_list
}
return render(request, 'list.html', ctx)
- 模板
<h3>标签云</h3>
<div class="widget-sentence-content">
<ul class="plinks ptags">
{% for t in tags %}
<li><a href="/tags/{{t.tid}}" title="{{t.name}}" draggable="false">{{t.name}} <span class="badge">{{t.count}}</span></a></li>
{% endfor %}
</ul>
</div>
</div>
十七、实现分类查询功能
- 编写视图
`def blog_list(request, cid=-1):`
post_list = None
if cid != -1:
cat = BlogCategory.objects.get(id=cid)
post_list = cat.post_set.all()
else:
post_list = Post.objects.all()
....
ctx = {
'post_list': post_list,
'tags': tag_message_list
}
return render(request, 'list.html', ctx)
- 编写路由
url(r'^category/(?P<cid>[0-9]+)/$', blog_list),
- 模板 index
<div class="title">
<h3>最新发布</h3>
<div class="more">
{%for c in blogcategory_list%}
<a href="/category/{{c.id}}" title="{{c.name}}" >{{c.name}}</a>
{% endfor %}
</div>
</div>
十八、实现按标签查询功能
- 编写views
`def blog_list(request, cid=-1, tid=-1):`
post_list = None
if cid != -1:
cat = BlogCategory.objects.get(id=cid)
post_list = cat.post_set.all()
elif tid != -1:
tag = Tags.objects.get(id=tid)
post_list = tag.post_set.all()
else:
post_list = Post.objects.all()
....
ctx = {
'post_list': post_list,
'tags': tag_message_list
}
return render(request, 'list.html', ctx)
- 路由设置
url(r'^tags/(?P<tid>[0-9]+)/$', blog_list),
- 模板
<h3>标签云</h3>
<div class="widget-sentence-content">
` <ul class="plinks ptags">`
`{% for t in tags %}`
` <li><a href="/tags/{{t.tid}}" title="{{t.name}}" draggable="false">{{t.name}} <span class="badge">{{t.count}}</span></a></li>`
`{% endfor %}`
` </ul>`
` </div>`
`</div>`
`</div>`
十九、实现博客详情功能
- 定义视图函数
`def blog_detail(request,bid):`
post = Post.objects.get(id=bid)
post.views = post.views + 1
post.save()
博客标签
tag_list = post.tags.all()
ctx = {
'post': post,
}
return render(request, 'show.html', ctx)
- 路由设置
url(r'^blog/(?P<bid>[0-9]+)/$', blog_detail, name='blog_detail'),
- 前端展示
{% extends 'base.html' %}
{% block title %}知奇博客-详细 {% endblock %}
{% block content %}
`<section class="container">`
`<div class="content-wrap">`
`<div class="content">`
<header class="article-header">
<h1 class="article-title"><a href="#" title="{{post.title}}" >{{post.title}}</a></h1>
<div class="article-meta"> <span class="item article-meta-time">
<time class="time" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="发表时间:{{post.pub_date|date:'Y-m-d'}}">
<i class="glyphicon glyphicon-time"></i> {{post.pub_date|date:'Y-m-d'}}</time>
</span>
<span class="item article-meta-source" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="来源:{{post.user.username}}">
<i class="glyphicon glyphicon-globe"></i> {{post.user.username}}</span>
<span class="item article-meta-category" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="{{post.category.name}}">
<i class="glyphicon glyphicon-list"></i> <a href="#" title="{{post.category.name}}" >{{post.category.name}}</a></span>
<span class="item article-meta-views" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="浏览量:{{post.views}}">
<i class="glyphicon glyphicon-eye-open"></i> {{post.views}}</span>
<span class="item article-meta-comment" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="评论量">
<i class="glyphicon glyphicon-comment"></i> </span> </div>
</header>
<article class="article-content">
<p>{{post.content}}</p>
</article>
<div class="article-tags">标签:
{% for tag in post.tags.all %}
<a href="/tags/{{tag.id}}">{{tag.name}}</a>
{% endfor %}
</div>
{% endblock %}
二十、实现相关推荐功能
- 编写视图
`def blog_detail(request, pid):`
post = Post.objects.get(id=pid)
post.views = post.views + 1
post.save()
comment_list = Comment.objects.order_by('-pub_date')
# 最新评论的博客 列表
new_comment_list = []
# 去重
for c in comment_list:
if c.post not in new_comment_list:
new_comment_list.append(c.post)
# 相关推荐
# 首先 我们需要取到 这篇文章的tag
tag_post_list = []
for tag in post.tags.all():
tag_post_list.extend(tag.post_set.all())
ctx = {
'post': post,
'new_comment_list': new_comment_list,
'tag_post_list': tag_post_list
}
return render(request, 'show.html', ctx)
- 模板
{% for tag_post in tag_post_list %}
<li><a href="{% url 'blog:detail' tag_post.id %}" title="">{{ tag_post.title }}</a></li>
{% endfor %}
二十一、实现发表评论的功能
* show.html
<h3>评论</h3>
</div>
<div id="respond">
<form id="comment-form" name="comment-form" action="/comment/{{post.id}}" method="POST">
<div class="comment">
<input name="username" id="" value="{{user.username}}" class="form-control" size="22" placeholder="您的昵称(必填)" maxlength="15" autocomplete="off" tabindex="1" type="text">
<!-- <input name="" id="" class="form-control" size="22" placeholder="您的网址或邮箱(非必填)" maxlength="58" autocomplete="off" tabindex="2" type="text"> -->
<div class="comment-box">
<textarea placeholder="您的评论或留言(必填)" name="content" id="comment-textarea" cols="100%" rows="3" tabindex="3"></textarea>
<div class="comment-ctrl">
<div class="comment-prompt" style="display: none;"> <i class="fa fa-spin fa-circle-o-notch"></i> <span class="comment-prompt-text">评论正在提交中...请稍后</span> </div>
<div class="comment-success" style="display: none;"> <i class="fa fa-check"></i> <span class="comment-prompt-text">评论提交成功...</span> </div>
<button type="submit" name="comment-submit" id="comment-submit" tabindex="4">评论</button>
</div>
</div>
</div>
{% csrf_token %}
</form>
- 编写视图类
`class CommentView(View):`
def get(self, request):
pass
def post(self, request, bid):
comment = Comment()
comment.user = request.user
comment.post = Post.objects.get(id=bid)
comment.content = request.POST.get('content')
comment.pub_date = datetime.now()
comment.save()
# Ajax
return HttpResponseRedirect(reverse("blog_detail", kwargs={"bid":bid}))
- 编写路由
url(r'^comment/(?P<bid>[0-9]+)$', CommentView.as_view(), name='comment'),
二十二、实现评论列表功能
- 编写视图
`def blog_detail(request,bid):`
post = Post.objects.get(id=bid)
post.views = post.views + 1
post.save()
# 最新评论博客
new_comment_list = Comment.objects.order_by('-pub_date').all()[:10]
comment_list = post.comment_set.all()
# 去重
new_comment_list1 = []
post_list1 = []
for c in new_comment_list:
if c.post.id not in post_list1:
new_comment_list1.append(c)
post_list1.append(c.post.id)
# 博客标签
tag_list = post.tags.all()
# 相关推荐(标签相同的)
post_recomment_list = set(Post.objects.filter(tags__in=tag_list)[:6])
ctx = {
'post': post,
'new_comment_list': new_comment_list1,
'post_recomment_list': post_recomment_list,
'comment_list': comment_list
}
return render(request, 'show.html', ctx)
{% for comment in comment_list %}
<li class="comment-content"><span class="comment-f">#{{forloop.counter}}</span><div class="comment-main"><p><a class="address" href="#" rel="nofollow" target="_blank">{{comment.user.username}}</a><span class="time">({{comment.pub_date|date:'Y-m-d'}})</span><br>{{comment.content}}</p></div></li>
{% endfor %}
网友评论