使用Django开发一个完整的博客项目

一、项目概述

项目运行环境

  1. Python3.6+
  2. Django 1.11
  3. MySQL 5.7
  4. 其他插件(图片处理、分页、验证码....)

项目详细功能介绍

前台功能

  1. 项目首页展示
  2. 轮播图
  3. 博客推荐
  4. 最新发布
  5. 博客分类
  6. 最新评论文章
  7. widgets小插件
  8. 搜索功能
  9. 博客分类功能
  10. 博客标签查询
  11. 友情链接
  12. 博客分页功能
  13. 博客详细
  14. 最新评论文章
  15. 发表评论
  16. 评论展示
  17. 评论数
  18. 阅读数
  19. 登录功能
  20. 注册功能
  21. 邮箱验证功能
  22. 注销功能
  23. 页面模板
  24. 标签云功能
  25. 读者墙功能

后台功能

  1. 用户维护
  2. 权限管理
  3. 博客分类维护
  4. 标签维护
  5. 友情链接
  6. 轮播图维护

项目演示

项目演示

项目代码演示

代码展示

二、开发环境搭建

使用virtualenv 和 virtualenwrapper

  1. MySQL 5.7
sudo apt install mysql-server mysql-client
  1. 安装mysql驱动
pip install pymysql
  1. 安装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)
  • 模板
  
  

  

八、实现博客推荐

  • 注册模型
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 %}
  
  {% 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%}

  

  {% 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 %}

十一、实现最新评论功能

  • 编写views
 

十二、实现搜索功能

  • 编写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()
    .....
  • 模板

        

友情链接

十四、实现博客列表功能

  • 编写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







{% block title %}知奇博客首页 {% endblock %}




{% block custom_css %}{% endblock %}













{% block content %} {% endblock %}

Copyright © 2016.Company name All rights reserved.

十五、实现分页功能

  • 安装包
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 %} {% endfor %} {% include "_pagination.html" %}
  • _pagination.html
{% load i18n %}


十六、实现标签云功能

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
        

    评论

    {% csrf_token %}
    • 编写视图类
    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}}

    {{comment.user.username}}({{comment.pub_date|date:'Y-m-d'}})
    {{comment.content}}

  • {% endfor %}

    二十三、实现登录功能

    
    {% extends 'base.html' %}
    {% block title %}知奇博客-详细 {% endblock %}
    
    {% block custom_css %}
    
    
    {% endblock %}
    
    
    {% block content %}
    
    
    

    {{error_msg}}

    {% csrf_token %}
    {% 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}}

    {% csrf_token %}
    {% 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目录,添加


      使用Django开发一个完整的博客项目_第1张图片
      选区_025

    创建一个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)
    

    你可能感兴趣的:(使用Django开发一个完整的博客项目)