{{post.content}}
【推荐】{{post.title}}
{{post.content}}
项目演示
代码展示
使用virtualenv 和 virtualenwrapper
sudo apt install mysql-server mysql-client
pip install pymysql
pip install django==1.11
django-admin startproject django-blog
python manage.py startapp userapp
python manage.py startapp blogapp
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
from django.contrib.auth.models import AbstractUser
class BlogUser(AbstractUser):
nikename = models.CharField('昵称', max_length=20, default='')
提示:需要在settings配置文件中设置:AUTH_USER_MODEL = 'users.BlogUser'
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)
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 = '轮播图'
class BlogCategory(models.Model):
name = models.CharField('分类名称', max_length=20, default='')
class Meta:
verbose_name = '博客分类'
verbose_name_plural = '博客分类'
def __str__(self):
return self.name
class Tags(models.Model):
name = models.CharField('标签名称', max_length=20, default='')
class Meta:
verbose_name = '标签'
verbose_name_plural = '标签'
def __str__(self):
return self.name
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 = '博客'
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 = '评论'
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(r'^$', index, name='index' )
from blogs.models import Banner
admin.site.register(Banner)
from .models import Banner
def index(request):
banner_list = Banner.objects.all()
ctx = {
'banner_list': banner_list,
}
return render(request, 'index.html', ctx)
from blogs.models import Banner,Post,BlogCategory,Tags
...
admin.site.register(BlogCategory)
admin.site.register(Tags)
admin.site.register(Post)
# 视图函数 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 %}
【推荐】{{post.title}}
{{post.content}}
{% endfor %}
# 视图函数 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%}
{{post.category.name}}
{{post.title}}
{% autoescape off %}
{{post.content | truncatechars_html:200}}
{% endautoescape %}
{% 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)
最新发布
{%for c in blogcategory_list%}
{{c.name}}
{% endfor %}
{% for post in new_comment_list %}
-
{{ post.title }}
{{ post.pub_date }}
{{ post.views }}
{% endfor %}
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)
url(r'^search$', SearchView.as_view(), name='search'),
def index(request):
....
friendlylink_list = FriendlyLink.objects.all()
.....
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'),
{% block title %}知奇博客首页 {% endblock %}
{% block custom_css %}{% endblock %}
{% block content %}
{% endblock %}
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)
博客列表
{% for post in post_list.object_list %}
{{post.category.name}}
{{post.title}}
{{post.content}}
{% endfor %}
{% include "_pagination.html" %}
- _pagination.html
{% load i18n %}
{% if post_list.has_previous %}
‹‹ 上一页
{% else %}
‹‹ 上一页
{% endif %}
{% for page in post_list.pages %}
{% if page %}
{% ifequal page post_list.number %}
{{ page }}
{% else %}
{{ page }}
{% endifequal %}
{% else %}
...
{% endif %}
{% endfor %}
{% if post_list.has_next %}
下一页 ››
{% else %}
下一页 ››
{% endif %}
十六、实现标签云功能
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)
- 模板
标签云
十七、实现分类查询功能
- 编写视图
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[0-9]+)/$', blog_list),
- 模板 index
最新发布
{%for c in blogcategory_list%}
{{c.name}}
{% endfor %}
十八、实现按标签查询功能
- 编写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[0-9]+)/$', blog_list),
- 模板
标签云
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[0-9]+)/$', blog_detail, name='blog_detail'),
{% extends 'base.html' %}
{% block title %}知奇博客-详细 {% endblock %}
{% block content %}
{{post.title}}
{{post.content}}
{% 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 %}
{{ tag_post.title }}
{% endfor %}
二十一、实现发表评论的功能
- show.html
评论
- 编写视图类
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[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 %}
#{{forloop.counter}}
{% endfor %}
二十三、实现登录功能
{% extends 'base.html' %}
{% block title %}知奇博客-详细 {% endblock %}
{% block custom_css %}
{% endblock %}
{% block content %}
{{error_msg}}
{% endblock %}
- 编写路由
url(r'^login/', LoginView.as_view(), name='login'),
- 编写视图
from django.shortcuts import render
from django.views.generic.base import View
from django.contrib.auth import authenticate, login, logout
class LoginView(View):
def get(self, request):
return render(request, 'login.html', {})
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse("index"))
else:
return render(request, 'login.html', {'error_msg':'用户未激活!'})
else:
return render(request, 'login.html', {'error_msg':'用户名或者密码错误!'})
- 修改模板 base.html
二十四、实现注册功能
{% extends 'base.html' %}
{% block title %}知奇博客-注册{% endblock %}
{% block custom_css %}
{% endblock %}
{% block content %}
{{error_msg}}
{% endblock %}
- 编写视图
from django.contrib.auth.hashers import make_password
....
class RegisterView(View):
def get(self, request):
return render(request, 'register.html')
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
email = request.POST.get('email')
# my_send_email(email)
user = BlogUser()
user.username = username
user.password = make_password(password)
user.email = email
user.is_active = False
user.save()
return render(request, 'login.html', {})
二十五、实现注册验证功能
- settings.py中配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
#发送邮件的邮箱
EMAIL_HOST_USER = 'xxx'
#在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = '123456'
#收件人看到的发件人
EMAIL_FROM = '知奇课堂'
- 视图函数
from random import Random
from django.core.mail import send_mail
from .models import EmailVerifyRecord
from blogpro.settings import EMAIL_FROM
# 生成随机字符串
def make_random_str(randomlength=8):
str = ''
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
length = len(chars) - 1
random = Random()
for i in range(randomlength):
str+=chars[random.randint(0, length)]
return str
# 发送邮件
def my_send_email(email, send_type="register"):
email_record = EmailVerifyRecord()
if send_type == "update_email":
code = make_random_str(4)
else:
code = make_random_str(16)
email_record.code = code
email_record.email = email
email_record.send_type = send_type
email_record.save()
email_title = ""
email_body = ""
if send_type == "register":
email_title = "知奇博客-注册激活链接"
email_body = "请点击下面的链接激活你的账号: http://127.0.0.1:8000/active/{0}".format(code)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
pass
elif send_type == "forget":
email_title = "知奇博客-网注册密码重置链接"
email_body = "请点击下面的链接重置密码: http://127.0.0.1:8000/reset/{0}".format(code)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
pass
elif send_type == "update_email":
email_title = "知奇博客-邮箱修改验证码"
email_body = "你的邮箱验证码为: {0}".format(code)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
pass
class ActiveView(View):
def get(self, request, active_code):
all_records = EmailVerifyRecord.objects.filter(code=active_code)
if all_records:
for record in all_records:
email = record.email
user = BlogUser.objects.get(email=email)
user.is_active = True
user.save()
else:
return render(request, "active_fail.html")
return render(request, "login.html")
- 路由设置
url(r'^login/', LoginView.as_view(), name='login'),
url(r'^register/', RegisterView.as_view(), name='register'),
url(r'^active/(?P[a-zA-Z0-9]+)', ActiveView.as_view(), name='active'),
url(r'^logout/', LogoutView.as_view(), name='logout'),
二十六、实现注销功能
class LogoutView(View):
def get(self, request):
logout(request)
return HttpResponseRedirect(reverse("index"))
二十七、实现后台富文本功能
下载kindeditor
地址: http://kindeditor.net/demo.php
-
配置
在static/js 下面创建一个editor目录,添加
创建一个config.js配置如下:
KindEditor.ready(function(K) {
window.editor = K.create('#editor_id',{
//指定大小
width:'800px',
height:'200px',
});
});
- 在admin中注册(blogs下面的admin.py中)
class PostAdmin(admin.ModelAdmin):
class Media:
js=(
'js/editor/kindeditor-all.js',
'js/editor/config.js',
)
admin.site.register(Post,PostAdmin)
{{comment.user.username}}({{comment.pub_date|date:'Y-m-d'}})
{{comment.content}}