zoukankan      html  css  js  c++  java
  • 饮冰三年-人工智能-Python-31博客园山寨版

    一 博客系统分析

    一、需求分析
            - 报障
                用户:
                    提交报账单
                    自己报障记录
                处理着:
                    查看所有人报障单
                    处理报账单
                    
            - 知识库(博客)
                主页:
                    展示最新文章
                    展示最热文章
                    展示评论最多文章
                    分类查看
                个人博客:
                    个人博客主页
                    个人博客文章详细:赞,踩,评论
                    个人博客分类:标签、分类、时间
                    个人博客主题定制:后台修改
                后台管理:
                    个人信息管理
                    个人标签
                    个人分类
                    个人文章
                
    二、数据库设计:        
            用户表: uid,username,pwd,email,img,
            博客表: bid,surfix,theme,title,summary, FK(用户表,unique)=OneToOne(用户表)
            互粉表: id  明星ID(用户表)   粉丝ID(用户表)       
            报障单:UUID   title   detail   user(用户表)   processor(用户表 null)  status(待处理,处理中,已处理)  创建时间  处理事件
            分类表:caption  Fk(博客bid)        
            标签表:caption  Fk(博客bid)       
            文章:id,title,summary,ctime,FK(个人分类表),主站分类(choices)        
            文章详细:detail  OneToOne(文章)        
            文章标签关系:  文章ID   标签ID       
            文章赞踩关系: 文章ID    用户ID   赞或踩(True,False)  联合唯一索引        
            文章评论表:id,content,FK(文章),FK(user),ctime,parent_comment_id 
            
    三、程序目录结构
        project
            - APP(repository) - 数据仓库(操作数据Model)
            - APP(backend)    - 后台管理
            - APP(web)        - 首页,个人博客
            - utils           - 工具包(公共模块)
            
    博客系统

     创建App命令:python manage.py startapp 名称

    并把相应的文件设置到setting配置中

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'repository',
        'backend',
    ]
    把app添加到配置文件中

    修改AaronBlogurl.py配置文件

    from django.contrib import admin
    from django.conf.urls import url
    from django.conf.urls import include
    urlpatterns = [
        url(r'^',include('web.urls')),
    ]
    Aaron/url.py

     添加static文件夹,并引入Bootstrap等文件

     model实体类

    from django.db import models
    
    
    # Create your models here.
    class UserInfo(models.Model):
        '''用户表'''
        uid = models.BigAutoField(primary_key=True)
        username = models.CharField(verbose_name="用户名", max_length=64, unique=True)
        pwd = models.CharField(verbose_name='密码', max_length=64)
        email = models.EmailField(verbose_name='邮箱', unique=True)
        img = models.ImageField(verbose_name='头像', null=True)
    
    
    class BlogInfo(models.Model):
        '''博客信息'''
        bid = models.BigAutoField(primary_key=True)
        surfix = models.CharField(verbose_name='博客后缀名', max_length=64)
        theme = models.CharField(verbose_name='博客主题', max_length=64)
        title = models.CharField(verbose_name='博客标题', max_length=1000)
        summary = models.CharField(verbose_name='博客简介', max_length=1000)
        user = models.OneToOneField(to="UserInfo", to_field="uid", on_delete=models.CASCADE, null=True)
    
    
    class UserFans(models.Model):
        '''互粉表'''
        starUser = models.ForeignKey(verbose_name='博主', to="UserInfo", to_field="uid", related_name="starUsers",
                                     on_delete=models.CASCADE, null=True)
        fansUser = models.ForeignKey(verbose_name='粉丝', to="UserInfo", to_field="uid", related_name='fansUsers',
                                     on_delete=models.CASCADE, null=True)
    
        class Meta:
            unique_together = [
                ('starUser', 'fansUser'),
            ]
    
    
    class ReportObstacles(models.Model):
        '''报障单'''
        uuid = models.UUIDField(primary_key=True)
        title = models.CharField(verbose_name="报障标题", max_length=1000)
        detail = models.TextField(verbose_name='报障详情')
        reportUser = models.ForeignKey(verbose_name='报修人', to="UserInfo", to_field="uid", related_name="reportUsers",
                                       on_delete=models.CASCADE, null=True)
        processUser = models.ForeignKey(verbose_name='处理人', to="UserInfo", to_field="uid", related_name="processUsers",
                                        on_delete=models.CASCADE, null=True)
        createTime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
        processTime = models.DateTimeField(verbose_name='处理时间', auto_now_add=True)
        type_status = [
            (1, '待处理'),
            (2, '处理中'),
            (3, '已处理'),
        ]
        status = models.IntegerField(choices=type_status, default=None)
    
    
    class Tag(models.Model):
        nid = models.AutoField(primary_key=True)
        title = models.CharField(verbose_name='标签名称', max_length=32)
        blog = models.ForeignKey(verbose_name='所属博客', to='BlogInfo', to_field='bid', on_delete=models.CASCADE, null=True)
    
    
    class Classification(models.Model):
        nid = models.AutoField(primary_key=True)
        title = models.CharField(verbose_name='分类名称', max_length=32)
        blog = models.ForeignKey(verbose_name='所属博客', to='BlogInfo', to_field='bid', on_delete=models.CASCADE, null=True)
    
    
    class Article(models.Model):
        nid = models.BigAutoField(primary_key=True)
        title = models.CharField(verbose_name='文章标题', max_length=128)
        summary = models.CharField(verbose_name='简介', max_length=256)
        blog = models.ForeignKey(verbose_name='所属博客', to='BlogInfo', to_field='bid', on_delete=models.CASCADE, null=True)
        create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
        classification_id = models.ForeignKey(verbose_name='文章分类', to='Classification', to_field="nid",
                                              on_delete=models.CASCADE, null=True)
        masterStation_type = [
            (1, "Python"),
            (2, "Linux"),
            (3, "OpenStack"),
            (4, "GoLang"),
        ]
        ms_Type = models.IntegerField(verbose_name='主站分类', choices=masterStation_type, default=None)
    
    
    class Article_Detail(models.Model):
        detail = models.TextField(verbose_name='文章详细', max_length=models.Max)
        article_id = models.OneToOneField(verbose_name='文章id', to='Article', to_field='nid', on_delete=models.CASCADE,
                                          null=True)
    
    
    class Article_Tag(models.Model):
        # 文章标签分类
        article_id = models.ForeignKey(verbose_name='文章ID', to='Article', to_field='nid', on_delete=models.CASCADE,
                                       null=True)
        tag_id = models.ForeignKey(verbose_name='标签ID', to='Tag', to_field='nid', on_delete=models.CASCADE, null=True)
    
    
    class Article_upDown(models.Model):
        # 文章标签分类
        article_id = models.ForeignKey(verbose_name='文章ID', to='Article', to_field='nid', on_delete=models.CASCADE,
                                       null=True)
        user = models.ForeignKey(verbose_name='赞或踩用户', to='UserInfo', to_field='uid',on_delete=models.CASCADE, null=True)
        up = models.BooleanField(verbose_name='是否赞', default=True)
    
        class Meta:
            unique_together = [
                ('article_id', 'user')
            ]
    
    
    class Article_Comment(models.Model):
        '''评论表'''
        id = models.BigAutoField(verbose_name='评论ID', primary_key=True)
        user = models.ForeignKey(verbose_name='评论人', to='UserInfo', to_field='uid', on_delete=models.CASCADE, null=True)
        comment = models.CharField(verbose_name='评论内容', max_length=1000)
        createTime = models.DateTimeField(verbose_name='评论时间', auto_now_add=True)
        reply = models.ForeignKey(verbose_name='回复评论', to='self', related_name='back', on_delete=models.CASCADE, null=True)
    实体类
    """AaronBlog URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/2.1/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    from django.contrib import admin
    from django.conf.urls import url
    from django.conf.urls import include
    urlpatterns = [
        url(r'^',include('web.urls')),
    ]
    AaronBlogurl.py
    from django.conf.urls import url
    from web.Views import home
    
    urlpatterns=[
        url(r'^all/(?P<ms_Type>d+).html$',home.index,name='index'),
        url(r'^', home.index),
    ]
    web下的url.py

    二:页面设置

    公用的css样式

    img{
        border: 0;
    }
    .left{
        float: left;
    }
    .right{
        float: right;
    }
    common.cs
    .article-item{
        font-size: 13px;
        border-bottom: 1px dashed #dddddd;
        padding:  5px 0;
    }
    .article-item h3{
        margin-top: 10px;
        font-size: 20px;
    }
    
    .article-item .avatar{
        border: 1px solid #d5d5d5;margin-right: 5px;
    }
    
    .article-item .avatar img{
         70px;height: 70px;padding: 1px;
    
    }
    .article-item .footers{
        padding: 5px 0 0 0;
    }
    
    .article-item .footers .ele{
        margin: 0 10px;
    }
    row_avatar

      1 index页面设置:

        1.1 导航条

        导航条设置成母版页,参考Bootstrap中的导航条,并引入相应的js和css    

    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <a class="navbar-brand" href="#">逍遥小天狼</a>
            </div>
    
            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    {% for item in article_tag_list %}
                        <li><a href="#">{{ item.1 }}</a></li>
                    {% endfor %}
                </ul>
    
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="#">登录</a></li>
                    <li><a href="#">注册</a></li>
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
    导航条

       1.2 数据展示,其中需要注意如何把统计后的赞、踩数统一返还给前端 

    article_list = models.Article.objects.filter(**kwargs).annotate(authorsNum=Count('article_updown'))
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
        <link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.css"/>
        <link rel="stylesheet" href="/static/css/common.css">
        <link rel="stylesheet" href="/static/css/row_avatar.css">
        <script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
        <script type="text/javascript" src="/static/plugins/bootstrap/js/bootstrap.js"></script>
    </head>
    <body>
    {% load staticfiles %}
    {% include 'Home/headTar.html' %}
    <div class="container">
        <div>
            <div class="col-md-8">
                <div class="article-list">
                    {% for article in article_list %}
                        <div class="article-item clearfix">
                            <h3><a href="#">{{ article.title }}</a></h3>
                            <div class="clearfix">
                                <a class="avatar left" href="#">
                                    <img src="/static/imgs/1.jpg">
                                </a>
                                {{ article.summary }}
                            </div>
                            <div class="footers">
                                <a href="#">
                                    <i class="fa fa-user-o" aria-hidden="true"></i>
                                    <span>{{ article.blog.user.username }}</span>
                                </a>
                                 <span>发布于 2019-02-06</span>
                                <a href="#" class="ele">
                                    <i class="fa fa-commenting-o" aria-hidden="true"></i>
                                    <span></span>
                                </a>
                                <a href="#" class="ele">
                                    <i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
                                    <span>{{ article.authorsNum }}</span>
                                </a>
                            </div>
                        </div>
                    {% endfor %}
                </div>
    
            </div>
        </div>
    </div>
    </body>
    </html>
    index.html
    from django.shortcuts import HttpResponse,render
    from repository import models
    from django.db.models import Count
    def index(request, *args, **kwargs):
        """
        博客首页,展示全部博文
        """
        # 设置标签列表(注意,该标签直接从model中获取)
        ms_Type = models.Article.masterStation_type
        # 判断是否有条件(主站分类:ms_Type)传递过来,
        article_list = models.Article.objects.filter(**kwargs).annotate(authorsNum=Count('article_updown'))
        current_ms_Type=0
        if kwargs:
            current_ms_Type= int(kwargs['ms_Type'])
    
        # 统计每一篇文章的赞、踩个数
        # bookList =models.Article.objects.annotate(authorsNum=Count('article_updown'))
    
    
        return render(request,"Home/index.html",{'masterStation_type':ms_Type,'article_list':article_list,'current_ms_Type':current_ms_Type})
    home.py

     1.3 分页功能   分页我们在python-26中有详细讲过,这里我们用自已定义一个分页组件

    # 2.1 所需要的参数
    # 序号          字段名             备注
    # a           data_count      列表的总个数
    # b           current_page_num当前页码
    # C           page_rows       每页显示多少行数据(每页显示10条)
    # D           page_num_size   页码条显示个数(建议为奇数,最多页面7个)
    # 2.2 方法具有的内容
    # 序号          字段名         备注
    # 1               start   当前页列表显示的初始值
    # 2               end     当前页列表显示的结束值
    # 3           page_count  总页数
    # 4           page_par_range  页码条显示范围
    
    class AaronPager(object):
        def __init__(self, data_count, current_page_num, page_rows=10, page_num_size=7,base_url='/'):
            # 数据总个数
            self.data_count = data_count
            # 当前页
            try:
                v = int(current_page_num)
                if v <= 0:
                    v = 1
                self.current_page_num = v
            except Exception as e:
                self.current_page_num = 1
            # 每页显示的行数
            self.page_rows = page_rows
            # 最多显示页面
            self.page_num_size = page_num_size
            #设置前台页面传递过来的url
            self.base_url=base_url
        def start(self):
            return (self.current_page_num - 1) * self.page_rows
    
        def end(self):
            return self.current_page_num * self.page_rows
    
        @property
        def page_count(self):
            # 总页数
            a, b = divmod(self.data_count, self.page_rows)
            if b == 0:
                return a
            return a + 1
    
        def page_par_range(self):
            #         总页数( self.page_count)     总页码数(self.page_num_size)   当前页(self.current_page_num)
            #         如果总页数<总页码数
            if self.page_count < self.page_num_size:
                return range(1, self.page_count + 1)
            # 如果当前页数<总页码数/2
            part = self.page_num_size // 2
            if self.current_page_num < part:
                return range(1, self.page_num_size + 1)
            # 如果当前页+part >总页码数
            if self.current_page_num + part > self.page_count:
                return range(self.page_count - self.page_num_size+1, self.page_count+1)
            return range(self.current_page_num - part, self.current_page_num + part+1)
    
        def page_str(self):
            page_list = []
            first = "<li><a href='%s?p=1'>首页</a></li>" %(self.base_url,)
            page_list.append(first)
            if self.current_page_num == 1:
                prev = "<li><a href='#'>上一页</a></li>"
            else:
                prev = "<li><a href='%s?p=%s'>上一页</a></li>" %(self.base_url,self.current_page_num - 1)
            page_list.append(prev)
            for i in self.page_par_range():
                if i==self.current_page_num:
                    temp = "<li class='active'><a href='%s?p=%s'>%s</a></li>" %(self.base_url,i,i)
                else:
                    temp = "<li><a href='%s?p=%s'>%s</a></li>" %(self.base_url,i,i)
                page_list.append(temp)
    
            if self.current_page_num == self.page_count:
                nex = "<li><a href='#'>下一页</a></li>"
            else:
                nex = "<li><a href='%s?p=%s'>下一页</a></li>" %(self.base_url,self.current_page_num + 1)
            page_list.append(nex)
            last = "<li><a href='%s?p=%s'>尾页</a></li>" %(self.base_url,self.page_count)
            page_list.append(last)
    
            return ''.join(page_list)
    分页模块

    给url起个别名,reverse方法通过别名生成url,以便于生成页码的链接

    from django.conf.urls import url
    from web.Views import home
    
    urlpatterns=[
    
        url(r'^all/(?P<ms_Type>d+).html$',home.index,name='index'),
        url(r'^', home.index),
    ]
    url

    home.py 文件做相应的修改

    from django.shortcuts import HttpResponse, render
    from repository import models
    from django.db.models import Count
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    from web.Views.Tools import AaronPager
    from django.urls import reverse
    
    def index(request, *args, **kwargs):
        """
        博客首页,展示全部博文
        """
        # 设置标签列表(注意,该标签直接从model中获取)
        ms_Type = models.Article.masterStation_type
        # 判断是否有条件(主站分类:ms_Type)传递过来,
        article_list = models.Article.objects.filter(**kwargs).annotate(authorsNum=Count('article_updown'))
        current_ms_Type = 0
        data_count = article_list.count()
        cur_page = request.GET.get('p')
        # reverse方法可以通过别名反向生成url
        base_url = '/'
        if kwargs:
            current_ms_Type = int(kwargs['ms_Type'])
            base_url = reverse('index', kwargs=kwargs)
            # 统计每一篇文章的赞、踩个数
            # bookList =models.Article.objects.annotate(authorsNum=Count('article_updown'))
        aaron_page = AaronPager.AaronPager(data_count, cur_page, 10, 7,base_url )
        article_list = article_list[aaron_page.start():aaron_page.end()]
        return render(request, "Home/index.html",
                      {'masterStation_type': ms_Type, 'article_list': article_list, 'current_ms_Type': current_ms_Type,'aaron_page':aaron_page,})
    home.py

    最后前台页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
        <link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.css"/>
        <link rel="stylesheet" href="/static/css/common.css">
        <link rel="stylesheet" href="/static/css/row_avatar.css">
        <script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
        <script type="text/javascript" src="/static/plugins/bootstrap/js/bootstrap.js"></script>
    </head>
    <body>
    {% load staticfiles %}
    {% include 'Home/headTar.html' %}
    <div class="container">
        <div>
            <div class="col-md-8">
                <div class="article-list">
                    {% for article in article_list %}
                        <div class="article-item clearfix">
                            <h3><a href="#">{{ article.title }}</a></h3>
                            <div class="clearfix">
                                <a class="avatar left" href="#">
                                    <img src="/static/imgs/1.jpg">
                                </a>
                                {{ article.summary }}
                            </div>
                            <div class="footers">
                                <a href="#">
                                    <i class="fa fa-user-o" aria-hidden="true"></i>
                                    <span>{{ article.blog.user.username }}</span>
                                </a>
                                <span>发布于 2019-02-06</span>
                                <a href="#" class="ele">
                                    <i class="fa fa-commenting-o" aria-hidden="true"></i>
                                    <span></span>
                                </a>
                                <a href="#" class="ele">
                                    <i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
                                    <span>{{ article.authorsNum }}</span>
                                </a>
                            </div>
                        </div>
                    {% endfor %}
                </div>
                <ul class="pagination pagination-sm">
                    {{ aaron_page.page_str|safe }}
                </ul>
            </div>
        </div>
    </div>
    </body>
    </html>
    index.html

     1.4 注册功能  我们通过Form表单实现

    创建form类

    from django import forms
    from django.forms import fields
    from django.core.validators import RegexValidator
    from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
    
    class AccountInfoForm(forms.Form):
        username = fields.CharField(
            required=True,
            label='用户名:',
            min_length=6,
            max_length=16,
            error_messages={
                'required': '用户名不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为16个字符',
            }
        )
        pwd = fields.CharField(
            label='密码:',
            required=True,
            min_length=6,
            max_length=16,
            validators=[RegexValidator(r'^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$\%^&*()])[0-9a-zA-Z!@#$\%^&*()]{8,32}$','密码过于简单(包含数字、字母的8位以上数字)')],
            error_messages={
                'required': '密码不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为16个字符',
            }
        )
        confirmPwd = fields.CharField(
            label='确认密码:',
            required=True,
            min_length=6,
            max_length=16,
            error_messages={
                'required': '密码不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为16个字符',
            }
        )
        email = fields.EmailField(
            label='邮箱:',
            required=True,
            min_length=6,
            max_length=18,
            error_messages={
                'required': '邮箱不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为18个字符',
                'invalid': '邮箱格式不正确',
            }
        )
        def clean(self):
            value_data = self.cleaned_data
            v1=value_data.get("pwd")
            v2=value_data.get("confirmPwd")
            if v1 != v2:
                self.add_error("confirmPwd", "密码不一致")
                raise ValidationError("密码不一致")
            return self.cleaned_data
    AccountInfoForm

    配置url地址

    from django.conf.urls import url
    from web.Views import home
    from  web.Views import account
    from django.urls import path
    
    urlpatterns=[
        url(r'^register.html$', account.register),
        url(r'^all/(?P<ms_Type>d+).html$',home.index,name='index'),
        url(r'^', home.index),
    ]
    url设置

    后台逻辑

    from django.shortcuts import render, redirect, HttpResponse
    from repository.models import UserInfo
    from web.Forms.Account import AccountInfoForm
    def register(request):
        # 注册用户
        if request.method == 'GET':
            obj = AccountInfoForm()
            print(obj)
            return render(request, "Account/register.html", {"obj": obj})
        else:
            obj = AccountInfoForm(request.POST)
            if obj.is_valid():
                UserInfo.objects.create(**obj.cleaned_data)
                return redirect('/')
            else:
                return render(request, "Account/register.html", {"obj": obj})
    用户注册

    前台页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="/register.html" method="post" novalidate>
        {% csrf_token %}
        <p>{{ obj.username.label }}{{ obj.username }}{{ obj.errors.username.0 }}</p>
        <p>  密 码 :{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
        <p>确认密码:{{ obj.confirmPwd }}{{ obj.errors.confirmPwd.0 }}</p>
        <p>  邮 箱 :{{ obj.email }}{{ obj.errors.email.0 }}</p>
        <input type="submit" value="注册"/>
    </form>
    </body>
    </html>
    前台html

    1.5  验证码模块

    首先安装bs4: pip install bs4

    引入生成验证码的模块

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import random
    from PIL import Image, ImageDraw, ImageFont, ImageFilter
    
    _letter_cases = "abcdefghjkmnpqrstuvwxy"  # 小写字母,去除可能干扰的i,l,o,z
    _upper_cases = _letter_cases.upper()  # 大写字母
    _numbers = ''.join(map(str, range(3, 10)))  # 数字
    init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
    
    
    def create_validate_code(size=(120, 30),
                             chars=init_chars,
                             img_type="GIF",
                             mode="RGB",
                             bg_color=(255, 255, 255),
                             fg_color=(0, 0, 255),
                             font_size=18,
                             font_type="simsun.ttc",
                             length=4,
                             draw_lines=True,
                             n_line=(1, 2),
                             draw_points=True,
                             point_chance=2):
        """
        @todo: 生成验证码图片
        @param size: 图片的大小,格式(宽,高),默认为(120, 30)
        @param chars: 允许的字符集合,格式字符串
        @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
        @param mode: 图片模式,默认为RGB
        @param bg_color: 背景颜色,默认为白色
        @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
        @param font_size: 验证码字体大小
        @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
        @param length: 验证码字符个数
        @param draw_lines: 是否划干扰线
        @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
        @param draw_points: 是否画干扰点
        @param point_chance: 干扰点出现的概率,大小范围[0, 100]
        @return: [0]: PIL Image实例
        @return: [1]: 验证码图片中的字符串
        """
    
        width, height = size  # 宽高
        # 创建图形
        img = Image.new(mode, size, bg_color)
        draw = ImageDraw.Draw(img)  # 创建画笔
    
        def get_chars():
            """生成给定长度的字符串,返回列表格式"""
            return random.sample(chars, length)
    
        def create_lines():
            """绘制干扰线"""
            line_num = random.randint(*n_line)  # 干扰线条数
    
            for i in range(line_num):
                # 起始点
                begin = (random.randint(0, size[0]), random.randint(0, size[1]))
                # 结束点
                end = (random.randint(0, size[0]), random.randint(0, size[1]))
                draw.line([begin, end], fill=(0, 0, 0))
    
        def create_points():
            """绘制干扰点"""
            chance = min(100, max(0, int(point_chance)))  # 大小限制在[0, 100]
    
            for w in range(width):
                for h in range(height):
                    tmp = random.randint(0, 100)
                    if tmp > 100 - chance:
                        draw.point((w, h), fill=(0, 0, 0))
    
        def create_strs():
            """绘制验证码字符"""
            c_chars = get_chars()
            strs = ' %s ' % ' '.join(c_chars)  # 每个字符前后以空格隔开
            font = ImageFont.truetype(font_type, font_size)
            font_width, font_height = font.getsize(strs)
    
            draw.text(((width - font_width) / 3, (height - font_height) / 3),
                      strs, font=font, fill=fg_color)
    
            return ''.join(c_chars)
    
        if draw_lines:
            create_lines()
        if draw_points:
            create_points()
        strs = create_strs()
    
        # 图形扭曲参数
        params = [1 - float(random.randint(1, 2)) / 100,
                  0,
                  0,
                  0,
                  1 - float(random.randint(1, 10)) / 100,
                  float(random.randint(1, 2)) / 500,
                  0.001,
                  float(random.randint(1, 2)) / 500
                  ]
        img = img.transform(size, Image.PERSPECTIVE, params)  # 创建扭曲
    
        img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)  # 滤镜,边界加强(阈值更大)
    
        return img, strs
    check_code.py
    __author__ = 'Administrator'
    from django.utils.safestring import mark_safe
    
    
    class Pagination(object):
        def __init__(self, current_page, data_count, per_page_count=10, pager_num=7):
            try:
                self.current_page = int(current_page)
            except Exception as e:
                self.current_page = 1
            self.data_count = data_count
            self.per_page_count = per_page_count
            self.pager_num = pager_num
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page_count
    
        @property
        def end(self):
            return self.current_page * self.per_page_count
    
        @property
        def total_count(self):
            v, y = divmod(self.data_count, self.per_page_count)
            if y:
                v += 1
            return v
    
        def page_str(self, base_url):
            page_list = []
    
            if self.total_count < self.pager_num:
                start_index = 1
                end_index = self.total_count + 1
            else:
                if self.current_page <= (self.pager_num + 1) / 2:
                    start_index = 1
                    end_index = self.pager_num + 1
                else:
                    start_index = self.current_page - (self.pager_num - 1) / 2
                    end_index = self.current_page + (self.pager_num + 1) / 2
                    if (self.current_page + (self.pager_num - 1) / 2) > self.total_count:
                        end_index = self.total_count + 1
                        start_index = self.total_count - self.pager_num + 1
    
            if self.current_page == 1:
                prev = '<li><a class="page" href="javascript:void(0);">上一页</a></li>'
            else:
                prev = '<li><a class="page" href="%s?p=%s">上一页</a></li>' % (base_url, self.current_page - 1,)
            page_list.append(prev)
    
            for i in range(int(start_index), int(end_index)):
                if i == self.current_page:
                    temp = '<li class="active"><a class="page active" href="%s?p=%s">%s</a></li>' % (base_url, i, i)
                else:
                    temp = '<li><a class="page" href="%s?p=%s">%s</a></li>' % (base_url, i, i)
                page_list.append(temp)
    
            if self.current_page == self.total_count:
                nex = '<li><a class="page" href="javascript:void(0);">下一页</a></li>'
            else:
                nex = '<li><a class="page" href="%s?p=%s">下一页</a></li>' % (base_url, self.current_page + 1,)
            page_list.append(nex)
    
            # jump = """
            # <input type='text'  /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
            # <script>
            #     function jumpTo(ths,base){
            #         var val = ths.previousSibling.value;
            #         location.href = base + val;
            #     }
            # </script>
            # """ % (base_url,)
            #
            # page_list.append(jump)
    
            page_str = mark_safe("".join(page_list))
    
            return page_str
    pagination.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from bs4 import BeautifulSoup
    
    
    class XSSFilter(object):
        __instance = None
    
        def __init__(self):
            # XSS白名单
            self.valid_tags = {
                "font": ['color', 'size', 'face', 'style'],
                'b': [],
                'div': [],
                "span": [],
                "table": [
                    'border', 'cellspacing', 'cellpadding'
                ],
                'th': [
                    'colspan', 'rowspan'
                ],
                'td': [
                    'colspan', 'rowspan'
                ],
                "a": ['href', 'target', 'name'],
                "img": ['src', 'alt', 'title'],
                'p': [
                    'align'
                ],
                "pre": ['class'],
                "hr": ['class'],
                'strong': []
            }
    
        def __new__(cls, *args, **kwargs):
            """
            单例模式
            :param cls:
            :param args:
            :param kwargs:
            :return:
            """
            if not cls.__instance:
                obj = object.__new__(cls, *args, **kwargs)
                cls.__instance = obj
            return cls.__instance
    
        def process(self, content):
            soup = BeautifulSoup(content, 'html.parser')
            # 遍历所有HTML标签
            for tag in soup.find_all(recursive=True):
                # 判断标签名是否在白名单中
                if tag.name not in self.valid_tags:
                    tag.hidden = True
                    if tag.name not in ['html', 'body']:
                        tag.hidden = True
                        tag.clear()
                    continue
                # 当前标签的所有属性白名单
                attr_rules = self.valid_tags[tag.name]
                keys = list(tag.attrs.keys())
                for key in keys:
                    if key not in attr_rules:
                        del tag[key]
    
            return soup.decode()
    
    
    if __name__ == '__main__':
        html = """<p class="title">
                            <b>The Dormouse's story</b>
                        </p>
                        <p class="story">
                            <div name='root'>
                                Once upon a time there were three little sisters; and their names were
                                <a href="http://example.com/elsie" class="sister c1" style='color:red;background-color:green;' id="link1"><!-- Elsie --></a>
                                <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
                                <a href="http://example.com/tillie" class="sister" id="link3">Tilffffffffffffflie</a>;
                                and they lived at the bottom of a well.
                                <script>alert(123)</script>
                            </div>
                        </p>
                        <p class="story">...</p>"""
    
        obj = XSSFilter()
        v = obj.process(html)
        print(v)
    xss.py

    生成验证码的代码很简单,

      前端的HTML添加一个图片路径   <p> 验证码:<img src="/check_code.html"></p>

      配置url信息  url(r'^check_code.html$',check_code.make_code),  

    import json
    
    from io import BytesIO
    from django.shortcuts import HttpResponse
    from django.shortcuts import render
    from django.shortcuts import redirect
    from utils.check_code import create_validate_code
    from repository import models
    def make_code(request):
        stream=BytesIO()
        img,code = create_validate_code()
        img.save(stream,'PNG')
        request.session['CheckCode']=code
        print(code)
        return HttpResponse(stream.getvalue())
    后台生成验证码逻辑

     1.6 把验证码也通过Form验证

      前端的HTML添加一个图片路径   < p> 验证码:{{ obj.checkCode }}{{ obj.errors.checkCode.0 }} <img src="/check_code.html" onclick="this.src=this.src+'?'"></p>

      难点在于,如何在Form表单中获取Session中保存的CheckCode,从而与用户输入的进行对比,以检验用户输入的是否正确

      方法,通过创建一个基础类BaseFrom,把页面上的request对象传进去  

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    class BaseForm(object):
        def __init__(self, request, *args, **kwargs):
            self.request = request
            super(BaseForm, self).__init__(*args, **kwargs)
    BaseForm

      然后在clean_checkCode方法中就可使用了  

    from django import forms
    from django.forms import fields
    from django.core.validators import RegexValidator
    from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
    from .base import BaseForm
    
    
    class AccountInfoForm(BaseForm,forms.Form):
        username = fields.CharField(
            required=True,
            label='用户名:',
            min_length=6,
            max_length=16,
            error_messages={
                'required': '用户名不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为16个字符',
            }
        )
        pwd = fields.CharField(
            label='密码:',
            required=True,
            min_length=6,
            max_length=16,
            validators=[
                RegexValidator(r'^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$\%^&*()])[0-9a-zA-Z!@#$\%^&*()]{8,32}$',
                               '密码过于简单(包含数字、字母的8位以上数字)')],
            error_messages={
                'required': '密码不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为16个字符',
            }
        )
        confirmPwd = fields.CharField(
            label='确认密码:',
            required=True,
            min_length=6,
            max_length=16,
            error_messages={
                'required': '密码不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为16个字符',
            }
        )
        email = fields.EmailField(
            label='邮箱:',
            required=True,
            min_length=6,
            max_length=18,
            error_messages={
                'required': '邮箱不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为18个字符',
                'invalid': '邮箱格式不正确',
            }
        )
    
        def clean(self):
            value_data = self.cleaned_data
            v1 = value_data.get("pwd")
            v2 = value_data.get("confirmPwd")
            if v1 != v2:
                self.add_error("confirmPwd", "密码不一致")
                raise ValidationError("密码不一致")
            return self.cleaned_data
    
        checkCode = fields.CharField(
            error_messages={
                'required': '验证码不能为空',
            }
        )
    
        def clean_checkCode(self):
            value_data = self.cleaned_data
            if self.request.session['CheckCode'].upper() != value_data.get("checkCode").upper():
                self.add_error("checkCode", "验证码错误")
                raise ValidationError(message='验证码错误', code='invalid')
    AccountInfoForm

      注意后台逻辑初始化的时候需要传递两个参数

    from django.shortcuts import render, redirect, HttpResponse
    from repository.models import UserInfo
    from web.Forms.Account import AccountInfoForm
    
    
    
    def register(request):
        # 注册用户
        if request.method == 'GET':
            obj = AccountInfoForm(request)
            return render(request, "Account/register.html", {"obj": obj})
        else:
            obj = AccountInfoForm(request,request.POST)
            if obj.is_valid():
    
                UserInfo.objects.create(**obj.cleaned_data)
                return redirect('/')
            else:
                return render(request, "Account/register.html", {"obj": obj})
    account.py

     1.7 用户登录

      登录成功以后,主要做(页面跳转、记录session、判断是否免登录)

      1.7.1 添加login.html页面  

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/css/account.css"/>
        <script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
    </head>
    <body>
    <div class="register">
        <div style="font-size: 25px; font-weight: bold;text-align: center;">
            用户登录
        </div>
        <form action="/login.html" method="post" novalidate>
            {% csrf_token %}
            <p>用户名:{{ obj.username }}{{ obj.errors.username.0 }}</p>
            <p> 密 码 :{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
            <p> 验证码:{{ obj.checkCode }}{{ obj.errors.checkCode.0 }} <img src="/check_code.html"
                                                                         onclick="this.src=this.src+'?'"></p>
            <div class="checkbox">
                <label>
                        {{ obj.rbm }} 一个月免登录
                </label>
                &nbsp;            &nbsp;
               <a href="#">忘记密码?</a>
            </div>
               <input type="submit" value="登录"/>
        </form>
    </div>
    <script type="text/javascript">
        $(function () {
            $("#id_pwd,#id_confirmPwd").attr("type","password")
        })
    </script>
    </body>
    </html>
    login.html

      1.7.2 配置url   

    url(r'^login.html$', account.login),

      1.7.3 设置DjangoForm表单 ,主要是LoginForm

    from django import forms
    from django.forms import fields
    from django.core.validators import RegexValidator
    from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
    from .base import BaseForm
    from repository.models import UserInfo
    
    class AccountInfoForm(BaseForm, forms.Form):
        username = fields.CharField(
            required=True,
            label='用户名:',
            min_length=6,
            max_length=16,
            error_messages={
                'required': '用户名不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为16个字符',
            }
        )
        pwd = fields.CharField(
            label='密码:',
            required=True,
            min_length=8,
            max_length=32,
            validators=[
                RegexValidator(r'^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$\%^&*()])[0-9a-zA-Z!@#$\%^&*()]{8,32}$',
                               '密码过于简单(包含数字、字母的8位以上数字)')],
            error_messages={
                'required': '密码不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为16个字符',
            }
        )
        confirmPwd = fields.CharField(
            label='确认密码:',
            required=True,
            min_length=8,
            max_length=32,
            error_messages={
                'required': '确认密码不能为空',
                'min_length': '至少为8个字符',
                'max_length': '最多为32个字符',
            }
        )
        email = fields.EmailField(
            label='邮箱:',
            required=True,
            min_length=6,
            max_length=18,
            error_messages={
                'required': '邮箱不能为空',
                'min_length': '至少为6个字符',
                'max_length': '最多为18个字符',
                'invalid': '邮箱格式不正确',
            }
        )
    
        checkCode = fields.CharField(
            error_messages={
                'required': '验证码不能为空',
            }
        )
    
        def clean(self):
            value_data = self.cleaned_data
            v1 = value_data.get("pwd")
            v2 = value_data.get("confirmPwd")
            if v1 != v2:
                self.add_error("confirmPwd", "密码不一致")
                raise ValidationError("密码不一致")
            return value_data
    
        def clean_checkCode(self):
            value_data = self.cleaned_data
            if self.request.session['CheckCode'].upper() != value_data.get("checkCode").upper():
                self.add_error("checkCode", "验证码错误")
                raise ValidationError(message='验证码错误', code='invalid')
            return value_data
        def clean_username(self):
            value =self.cleaned_data.get("username")
            if UserInfo.objects.filter(username=value):
                self.add_error("username", "用户名已存在")
            return value
        def clean_email(self):
            value = self.cleaned_data['email']
            if UserInfo.objects.filter(email=value):
                self.add_error("email", "邮箱已存在")
            return value
    
    class LoginForm(BaseForm,forms.Form):
        username = fields.CharField(
            error_messages={
                'required': '用户名不能为空',
            }
        )
        pwd = fields.CharField(
            error_messages={
                'required': '密码不能为空',
            })
        checkCode = fields.CharField(
            error_messages={'required': '验证码不能为空.'}
        )
        rbm = fields.BooleanField(
            required=False,
        )
        def clean_checkCode(self):
            value_data = self.cleaned_data
            if self.request.session['CheckCode'].upper() != value_data.get("checkCode").upper():
                self.add_error("checkCode", "验证码错误")
                raise ValidationError(message='验证码错误', code='invalid')
            return value_data
        def clean(self):
            userName =self.cleaned_data.get("username")
            pwd =self.cleaned_data.get("pwd")
            # 可以使用Q查询 Q(username=userName) & Q(pwd=pwd)
            userInfo = UserInfo.objects.filter(username=userName,pwd=pwd)
            print(self.cleaned_data.get('rbm'))
    
            if userInfo:
                # 记录session,可用于修改headTar中的状态。
                self.request.session['user_info'] = userInfo.values(
                           'username').first()
                # 如果勾选了30免登陆,设置session的过期时间
                if self.cleaned_data.get('rbm'):
                    self.request.session.set_expiry(60 * 60 * 24 * 7)
            else:
                self.add_error("username", "用户名不存在或密码错误")
                raise ValidationError(message='用户名不存在或密码错误', code='invalid')
            return self.cleaned_data
    Account.py

      1.7.4 设置后台处理逻辑,主要login

    from django.shortcuts import render, redirect, HttpResponse
    from repository.models import UserInfo
    from web.Forms.Account import AccountInfoForm,LoginForm
    
    def register(request):
        # 注册用户
        if request.method == 'GET':
            obj = AccountInfoForm(request)
            return render(request, "Account/register.html", {"obj": obj})
        else:
            obj = AccountInfoForm(request,request.POST)
            if obj.is_valid():
                del obj.cleaned_data["confirmPwd"]
                del obj.cleaned_data["checkCode"]
                # 我不知道这个数据值什么时候丢的,
                # obj.cleaned_data["email"]=request.POST.get("email") #发现是clean_XX方法没有了写返回值
                UserInfo.objects.create(**obj.cleaned_data)
                return redirect('/')
            else:
                return render(request, "Account/register.html", {"obj": obj})
    
    def login(request):
        #登陆用户
        if request.method == 'GET':
            obj = LoginForm(request)
            return render(request, "Account/login.html", {"obj": obj})
        else:
            obj = LoginForm(request, request.POST)
            if obj.is_valid():
                del obj.cleaned_data["checkCode"]
                return redirect('/')
            else:
                return render(request, "Account/login.html", {"obj": obj})
    
    def logout(request):
        request.session['user_info'] = None
        return redirect('/')
    account.py

      1.7.5 一个月免登陆  

    def login(request):
        #登陆用户
        if request.method == 'GET':
            obj = LoginForm(request)
            return render(request, "Account/login.html", {"obj": obj})
        else:
            obj = LoginForm(request, request.POST)
            if obj.is_valid():
                del obj.cleaned_data["checkCode"]
                if(obj.cleaned_data["rbm"]) :
                    request.session.set_expiry(60 * 60 * 24 * 7)
                # 通过用户信息 获取博客信息 ,进一步拿到博客的后缀名,跳转到个人主页
                # UserInfo(UserID)==》BlogInfo(surfix)
                userInfo=UserInfo.objects.filter(username=obj.cleaned_data["username"]).select_related("bloginfo").first()
                if userInfo.bloginfo.surfix:
                    base_url = '/'
                    base_url = reverse('home', kwargs={'site':userInfo.bloginfo.surfix})
                    return redirect(base_url)
                else:
                    return redirect('/')
            else:
                return render(request, "Account/login.html", {"obj": obj})
    account.py

    1.8 个人主页

     登录成功以后,需要进行页面跳转。

    1.8.1 左侧结构

    配置url信息:  url(r'^(?P<site>w+).html$', home.home,name='home'),

    前后台页面

    def home(request, site):
        """
        博主个人首页
        :param request:
        :param site: 博主的网站后缀如:http://xxx.com/Aaron.html
        :return:
        """
        # 根据后缀名获取博客信息
        blogInfo=models.BlogInfo.objects.filter(surfix=site).select_related("user").first()
        if not blogInfo:
            return redirect('/')
        else:
            # 获取分类信息                            这种写法想当于 blog = blogInfo.id
            category_list = models.Classification.objects.filter(blog=blogInfo)
            # 获取标签信息
            tag_list=models.Tag.objects.filter(blog=blogInfo)
            #获取日期,这种系原生的sql
            date_list = models.Article.objects.raw(
                'select nid, count(nid) as num,strftime("%Y-%m",create_time) as ctime from repository_article group by strftime("%Y-%m",create_time)')
            # 获取文章信息
            article_list=models.Article.objects.filter(blog=blogInfo).order_by('-nid').all()
            print(article_list)
            #
            return render(request, "Home/home.html", { 'blog': blogInfo,
                'tag_list': tag_list,
                'category_list': category_list,
                'date_list': date_list,
                'article_list': article_list})
    后台view方法
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
        <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/>
        <link rel="stylesheet" href="/static/css/edmure.css"/>
        <link rel="stylesheet" href="/static/css/common.css"/>
        <link rel="stylesheet" href="/static/css/row_avatar.css"/>
        <link rel="stylesheet" href="/static/css/theme/{{ blog.theme }}.css"/>
        {% block css %}{% endblock %}
        <script type="text/javascript" src="/static/js/jquery-1.12.4.js"></script>
        <script type="text/javascript" src="/static/plugins/bootstrap/js/bootstrap.js"></script>
    </head>
    <body>
    <div class="pg-header">
        <div class="title">{{ blog.title }}</div>
        <div class="menu-list">
            <a class="menu-item" href="/">首页</a>
            <a class="menu-item" href="/{{ blog.site }}.html">个人首页</a>
            <a class="menu-item" href="/backend/index.html">管理</a>
        </div>
    </div>
    <div class="pg-body">
        <div class="body-menu">
            <div class="notice">
                <div class="notice-header">公告</div>
                <div class="notice-body">
                    <ul>
                        <li>昵称:{{ blog.user.nickname }}</li>
                        <li>粉丝:{{ blog.user.fans.count }}</li>
                        <li>关注:{{ blog.user.f.count }}</li>
                        <li>邮箱:{{ blog.user.email }}</li>
                    </ul>
                    <div class="memo">
                        真实是人生的命脉,是一切价值的根基。
                    </div>
                </div>
            </div>
            <div class="tags">
                <div class="tags-header">标签</div>
                <div class="tags-body">
                    <ul>
                        {% for tag in tag_list %}
                            <li><a href="/{{ blog.site }}/tag/{{ tag.nid }}.html">{{ tag.title }}({{ tag.article_set.count }})</a></li>
                        {% endfor %}
                    </ul>
                </div>
            </div>
            <div class="types">
                <div class="types-header">分类</div>
                <div class="types-body">
                    <ul>
                        {% for tag in category_list %}
                            <li><a href="/{{ blog.site }}/category/{{ tag.nid }}.html">{{ tag.title }}({{ tag.article_set.count }})</a></li>
                        {% endfor %}
                    </ul>
                </div>
            </div>
            <div class="dates">
                <div class="dates-header">时间</div>
                <div class="dates-body">
                    <ul>
                        {% for tag in date_list %}
                            <li><a href="/{{ blog.site }}/date/{{ tag.ctime }}.html">{{ tag.ctime}}({{ tag.num}})</a></li>
                        {% endfor %}
                    </ul>
                </div>
            </div>
        </div>
        <div class="body-content">
            {% block content %}{% endblock %}
        </div>
    </div>
        {% block js %}{% endblock %}
    </body>
    </html>
    home_layout.html

     1.8.2 筛选功能

    配置条件:url(r'^(?P<site>w+)/(?P<condition>((tag)|(date)|(category)))/(?P<val>w+-*w*).html$', home.filter),

     后台处理逻辑:

    from django.shortcuts import HttpResponse,redirect, render
    from repository import models
    from django.db.models import Count
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    from web.Views.Tools import AaronPager
    from django.urls import reverse
    import time
    def index(request, *args, **kwargs):
        """
        博客首页,展示全部博文
        """
        # 设置标签列表(注意,该标签直接从model中获取)
        ms_Type = models.Article.masterStation_type
        # 判断是否有条件(主站分类:ms_Type)传递过来,
        article_list = models.Article.objects.filter(**kwargs).annotate(authorsNum=Count('article_updown'))
        current_ms_Type = 0
        data_count = article_list.count()
        cur_page = request.GET.get('p')
        # reverse方法可以通过别名反向生成url
        base_url = '/'
        if kwargs:
            current_ms_Type = int(kwargs['ms_Type'])
            base_url = reverse('index', kwargs=kwargs)
            # 统计每一篇文章的赞、踩个数
            # bookList =models.Article.objects.annotate(authorsNum=Count('article_updown'))
        aaron_page = AaronPager.AaronPager(data_count, cur_page, 10, 7,base_url )
        article_list = article_list[aaron_page.start():aaron_page.end()]
        return render(request, "Home/index.html",
                      {'masterStation_type': ms_Type, 'article_list': article_list, 'current_ms_Type': current_ms_Type,'aaron_page':aaron_page,})
    
    def home(request, site):
        """
        博主个人首页
        :param request:
        :param site: 博主的网站后缀如:http://xxx.com/Aaron.html
        :return:
        """
        # 根据后缀名获取博客信息
        blogInfo=models.BlogInfo.objects.filter(surfix=site).select_related("user").first()
        if not blogInfo:
            return redirect('/')
        else:
            # 获取分类信息                            这种写法想当于 blog = blogInfo.id
            category_list = models.Article.objects.filter(blog=blogInfo).select_related("classification_id").values("classification_id","classification_title").annotate(num=Count('classification_id'))
            str = 'select a.nid as nid,a.title as title,count(b.nid) as num  from repository_classification a LEFT JOIN  repository_article b on b.blog_id = a.blog_id and a.nid=b.classification_id_id where a.blog_id =%(n1)d GROUP BY (a.nid)' %{"n1":blogInfo.bid}
            # category_list = models.Classification.objects.raw(str)
            # 获取标签信息
            #tag_list=models.Tag.objects.filter(blog=blogInfo).annotate(Num=Count('article.article_set'))
            str = ' select a.nid as nid,a.title as title ,count(c.nid) as num  from repository_Tag a INNER JOIN repository_article_tag b on a.nid=b.tag_id_id LEFT JOIN  repository_article c on c.blog_id = a.blog_id and c.nid=b.article_id_id where a.blog_id =%(n1)d  GROUP BY (a.nid)' %{"n1":blogInfo.bid}
            tag_list = models.Tag.objects.raw(str)
            #获取日期,这种系原生的sql
            str='select nid, count(nid) as num,strftime("%%Y-%%m",create_time) as ctime from repository_article where blog_id =%(n1)d group by strftime("%%Y-%%m",create_time)' %{"n1":blogInfo.bid}
            date_list = models.Article.objects.raw(str)
            # 获取文章信息
            article_list=models.Article.objects.filter(blog=blogInfo).order_by('-nid').all()
            #
            return render(request, "Home/home.html", { 'blog': blogInfo,
                'tag_list': tag_list,
                'category_list': category_list,
                'date_list': date_list,
                'article_list': article_list})
    
    
    def filter(request,site,condition,val):
        blog = models.BlogInfo.objects.filter(surfix=site).select_related('user').first()
        if not blog:
            return redirect('/')
        # tag_list=models.Tag.objects.filter(blog=blog) #标签
        str = ' select a.nid as nid,a.title as title ,count(c.nid) as num  from repository_Tag a INNER JOIN repository_article_tag b on a.nid=b.tag_id_id LEFT JOIN  repository_article c on c.blog_id = a.blog_id and c.nid=b.article_id_id where a.blog_id =%(n1)d  GROUP BY (a.nid)' % {
            "n1": blog.bid}
        tag_list = models.Tag.objects.raw(str)
        # category_list=models.Classification.objects.filter(blog=blog).select_related("article").annotate(Num=Count('article')) #分类
        str = 'select a.nid as nid,a.title as title,count(b.nid) as num  from repository_classification a LEFT JOIN  repository_article b on b.blog_id = a.blog_id and a.nid=b.classification_id_id where a.blog_id =%(n1)d GROUP BY (a.nid)' % {
            "n1": blog.bid}
        category_list = models.Classification.objects.raw(str)
        str = 'select nid, count(nid) as num,strftime("%%Y-%%m",create_time) as ctime from repository_article where blog_id =%(n1)d group by strftime("%%Y-%%m",create_time)' % {
            "n1": blog.bid}
        date_list = models.Article.objects.raw(str)
        template_name="Home/home_summary_list.html"
        if condition=="tag":
            template_name="Home/home_title_list.html"
            article_list=models.Article.objects.filter(tags=val,blog=blog).all()
        elif condition=="category":
            article_list=models.Article.objects.filter(classification_id=val,blog=blog).all()
            print(article_list)
        elif condition == 'date':
            article_list = models.Article.objects.filter(blog=blog).extra(
                where=['strftime("%%Y-%%m",create_time)=%s'], params=[val, ]).all()
        else:
            article_list = []
    
        return render(
            request,
            template_name,
            {
                'blog': blog,
                'tag_list': tag_list,
                'category_list': category_list,
                'date_list': date_list,
                'article_list': article_list
            }
        )
    filter

     前台处理页面:

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
        <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/>
        <link rel="stylesheet" href="/static/css/edmure.css"/>
        <link rel="stylesheet" href="/static/css/common.css"/>
        <link rel="stylesheet" href="/static/css/row_avatar.css"/>
        <link rel="stylesheet" href="/static/css/theme/{{ blog.theme }}.css"/>
        {% block css %}{% endblock %}
        <script type="text/javascript" src="/static/js/jquery-1.12.4.js"></script>
        <script type="text/javascript" src="/static/plugins/bootstrap/js/bootstrap.js"></script>
    </head>
    <body>
    <div class="pg-header">
        <div class="title">{{ blog.title }}</div>
        <div class="menu-list">
            <a class="menu-item" href="/">首页</a>
            <a class="menu-item" href="/{{ blog.surfix }}.html">个人首页</a>
            <a class="menu-item" href="/backend/index.html">管理</a>
        </div>
    </div>
    <div class="pg-body">
        <div class="body-menu">
            <div class="notice">
                <div class="notice-header">公告</div>
                <div class="notice-body">
                    <ul>
                        <li>昵称:{{ blog.user.nickname }}</li>
                        <li>粉丝:{{ blog.user.fans.count }}</li>
                        <li>关注:{{ blog.user.f.count }}</li>
                        <li>邮箱:{{ blog.user.email }}</li>
                    </ul>
                    <div class="memo">
                        真实是人生的命脉,是一切价值的根基。
                    </div>
                </div>
            </div>
            <div class="tags">
                <div class="tags-header">标签</div>
                <div class="tags-body">
                    <ul>
                        {% for tag in tag_list %}
                            <li><a href="/{{ blog.surfix }}/tag/{{ tag.nid }}.html">{{ tag.title }}({{ tag.num }})</a></li>
                        {% endfor %}
                    </ul>
                </div>
            </div>
            <div class="types">
                <div class="types-header">分类</div>
                <div class="types-body">
                    <ul>
                        {% for tag in category_list %}
                            <li><a href="/{{ blog.surfix }}/category/{{ tag.nid }}.html">{{ tag.title }}({{ tag.num}})</a></li>
                        {% endfor %}
                    </ul>
                </div>
            </div>
            <div class="dates">
                <div class="dates-header">时间</div>
                <div class="dates-body">
                    <ul>
                        {% for tag in date_list %}
                            <li><a href="/{{ blog.surfix }}/date/{{ tag.ctime }}.html">{{ tag.ctime}}({{ tag.num}})</a></li>
                        {% endfor %}
                    </ul>
                </div>
            </div>
        </div>
        <div class="body-content">
            {% block content %}{% endblock %}
        </div>
    </div>
        {% block js %}{% endblock %}
    </body>
    </html>
    home_layout.html
    {% extends 'Home/home_layout.html' %}
    {% block content %}
        <div class="title-list">
    
    
            {% for row in article_list %}
            <div class="row-item">
                <div class="title">
                    <a href="/{{ blog.site }}/{{ row.nid }}.html">{{ row.title }}</a>
                </div>
                <div class="tips">
                    <span>{{ blog.user.nickname }}</span>
                    <span>{{ row.create_time|date:"Y-m-d H:i:s" }} </span>
                    <span>
                        <i class="fa fa-commenting-o" aria-hidden="true"></i>
                        <span>{{ row.comment_count }}</span>
                    </span>
                    <span>
                        <i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
                        <span>{{ row.up_count }}</span>
                    </span>
                </div>
            </div>
            {% endfor %}
        </div>
    {% endblock %}
    home_title_list
    {% extends 'Home/home_layout.html' %}
    {% block content %}
        <div class="summary-list">
            {% for row in article_list %}
                <div class="summary-item" style="border-bottom: 1px solid #dddddd;padding: 8px 0;">
                    <div class="summary-title">
                        <a href="/{{ blog.site }}/{{ row.nid }}.html">{{ row.title }}</a>
                    </div>
                    <div class="summary-content">
                        {{ row.summary }}
                    </div>
                    <div class="summary-footer">
                        <span>{{ row.create_time|date:"Y-m-d H:i:s" }}</span>
                        <span>{{ row.user.nickname }}</span>
                        <span>阅读({{ row.read_count }})</span>
                        <a>评论({{ row.comment_count }})</a>
                        <a href="/backend/edit-article-{{ row.nid }}.html">编辑</a>
                    </div>
                </div>
            {% endfor %}
        </div>
    {% endblock %}
    home_summary_list.html

    1.8.3 右侧展示页面

    1.8.3.1 标签下面的页面 home_title_list.html

    1.8.3.2 分类下面的页面 home_summary_list.html

    1.8.3.3 文章最终页

     为了查询的快捷,可以为文章表添加四个冗余字段

    class Article(models.Model):
        nid = models.BigAutoField(primary_key=True)
        title = models.CharField(verbose_name='文章标题', max_length=128)
        summary = models.CharField(verbose_name='简介', max_length=256)
        blog = models.ForeignKey(verbose_name='所属博客', to='BlogInfo', to_field='bid', on_delete=models.CASCADE, null=True)
        create_time = models.DateTimeField(verbose_name='创建时间', null=False)
        read_count = models.IntegerField(verbose_name='阅读数量',default=0)
        comment_count = models.IntegerField(verbose_name='评论数量',default=0)
        up_count = models.IntegerField(verbose_name='点赞数量',default=0)
        down_count = models.IntegerField(verbose_name='踩数量',default=0)
        classification_id = models.ForeignKey(verbose_name='文章分类', to='Classification', to_field="nid",
                                              on_delete=models.CASCADE, null=True)
        masterStation_type = [
            (1, "Python"),
            (2, "Linux"),
            (3, "OpenStack"),
            (4, "GoLang"),
        ]
        ms_Type = models.IntegerField(verbose_name='主站分类', choices=masterStation_type, default=None)
        tags=models.ManyToManyField(
            to='Tag',
            through='Article_Tag',
            through_fields=('article_id','tag_id')
        )
    article的model
    from django.shortcuts import HttpResponse,redirect, render
    from repository import models
    from django.db.models import Count
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    from web.Views.Tools import AaronPager
    from django.urls import reverse
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    import time
    import json
    def index(request, *args, **kwargs):
        """
        博客首页,展示全部博文
        """
        # 设置标签列表(注意,该标签直接从model中获取)
        ms_Type = models.Article.masterStation_type
        # 判断是否有条件(主站分类:ms_Type)传递过来,
        article_list = models.Article.objects.filter(**kwargs).annotate(authorsNum=Count('article_updown'))
        current_ms_Type = 0
        data_count = article_list.count()
        cur_page = request.GET.get('p')
        # reverse方法可以通过别名反向生成url
        base_url = '/'
        if kwargs:
            current_ms_Type = int(kwargs['ms_Type'])
            base_url = reverse('index', kwargs=kwargs)
            # 统计每一篇文章的赞、踩个数
            # bookList =models.Article.objects.annotate(authorsNum=Count('article_updown'))
        aaron_page = AaronPager.AaronPager(data_count, cur_page, 10, 7,base_url )
        article_list = article_list[aaron_page.start():aaron_page.end()]
        return render(request, "Home/index.html",
                      {'masterStation_type': ms_Type, 'article_list': article_list, 'current_ms_Type': current_ms_Type,'aaron_page':aaron_page,})
    
    def home(request, site):
        """
        博主个人首页
        :param request:
        :param site: 博主的网站后缀如:http://xxx.com/Aaron.html
        :return:
        """
        # 根据后缀名获取博客信息
        blogInfo=models.BlogInfo.objects.filter(surfix=site).select_related("user").first()
        if not blogInfo:
            return redirect('/')
        else:
            # 获取分类信息                            这种写法想当于 blog = blogInfo.id
            #category_list = models.Article.objects.filter(blog=blogInfo).select_related("classification_id").values("classification_id","title").annotate(num=Count('classification_id'))
            str = 'select a.nid as nid,a.title as title,count(b.nid) as num  from repository_classification a LEFT JOIN  repository_article b on b.blog_id = a.blog_id and a.nid=b.classification_id_id where a.blog_id =%(n1)d GROUP BY (a.nid)' %{"n1":blogInfo.bid}
            category_list = models.Classification.objects.raw(str)
            # 获取标签信息
            #tag_list=models.Tag.objects.filter(blog=blogInfo).annotate(Num=Count('article.article_set'))
            str = ' select a.nid as nid,a.title as title ,count(c.nid) as num  from repository_Tag a INNER JOIN repository_article_tag b on a.nid=b.tag_id_id LEFT JOIN  repository_article c on c.blog_id = a.blog_id and c.nid=b.article_id_id where a.blog_id =%(n1)d  GROUP BY (a.nid)' %{"n1":blogInfo.bid}
            tag_list = models.Tag.objects.raw(str)
            #获取日期,这种系原生的sql
            str='select nid, count(nid) as num,strftime("%%Y-%%m",create_time) as ctime from repository_article where blog_id =%(n1)d group by strftime("%%Y-%%m",create_time)' %{"n1":blogInfo.bid}
            date_list = models.Article.objects.raw(str)
            # 获取文章信息
            article_list=models.Article.objects.filter(blog=blogInfo).order_by('-nid').all()
            #
            return render(request, "Home/home.html", { 'blog': blogInfo,
                'tag_list': tag_list,
                'category_list': category_list,
                'date_list': date_list,
                'article_list': article_list})
    
    def filter(request,site,condition,val):
        blog = models.BlogInfo.objects.filter(surfix=site).select_related('user').first()
    
        if not blog:
            return redirect('/')
        # tag_list=models.Tag.objects.filter(blog=blog) #标签
        str = ' select a.nid as nid,a.title as title ,count(c.nid) as num  from repository_Tag a INNER JOIN repository_article_tag b on a.nid=b.tag_id_id LEFT JOIN  repository_article c on c.blog_id = a.blog_id and c.nid=b.article_id_id where a.blog_id =%(n1)d  GROUP BY (a.nid)' % {
            "n1": blog.bid}
        tag_list = models.Tag.objects.raw(str)
    
        str = 'select a.nid as nid,a.title as title,count(b.nid) as num  from repository_classification a LEFT JOIN  repository_article b on b.blog_id = a.blog_id and a.nid=b.classification_id_id where a.blog_id =%(n1)d GROUP BY (a.nid)' % {
            "n1": blog.bid}
        category_list = models.Classification.objects.raw(str)
        str = 'select nid, count(nid) as num,strftime("%%Y-%%m",create_time) as ctime from repository_article where blog_id =%(n1)d group by strftime("%%Y-%%m",create_time)' % {
            "n1": blog.bid}
        date_list = models.Article.objects.raw(str)
        template_name="Home/home_summary_list.html"
        if condition=="tag":
            template_name="Home/home_title_list.html"
            article_list=models.Article.objects.filter(tags=val,blog=blog).all()
        elif condition=="category":
            article_list=models.Article.objects.filter(classification_id=val,blog=blog).all()
            print(article_list)
        elif condition == 'date':
            article_list = models.Article.objects.filter(blog=blog).extra(
                where=['strftime("%%Y-%%m",create_time)=%s'], params=[val, ]).all()
        else:
            article_list = []
    
        return render(
            request,
            template_name,
            {
                'blog': blog,
                'tag_list': tag_list,
                'category_list': category_list,
                'date_list': date_list,
                'article_list': article_list
            }
        )
    
    def detail(request, site, nid):
        cur_page = request.GET.get('p')
        blogInfo=models.BlogInfo.objects.filter(surfix=site).select_related("user").first()
        # 这样关联如果可以的话,那实在是太厉害了
        article=models.Article.objects.filter(blog=blogInfo,nid=nid).select_related("article_detail","classification_id").first();
        comment_list = models.Article_Comment.objects.filter(article=article).select_related("reply")
        aaron_page = AaronPager.AaronPager(comment_list.count(), cur_page, 5, 7,nid + '.html')
        comment_list = comment_list[aaron_page.start():aaron_page.end()]
        # tag_list=models.Tag.objects.filter(blog=blog) #标签
        str = ' select a.nid as nid,a.title as title ,count(c.nid) as num  from repository_Tag a INNER JOIN repository_article_tag b on a.nid=b.tag_id_id LEFT JOIN  repository_article c on c.blog_id = a.blog_id and c.nid=b.article_id_id where a.blog_id =%(n1)d  GROUP BY (a.nid)' % {
            "n1": blogInfo.bid}
        tag_list = models.Tag.objects.raw(str)
        # category_list=models.Classification.objects.filter(blog=blog).select_related("article").annotate(Num=Count('article')) #分类
        str = 'select a.nid as nid,a.title as title,count(b.nid) as num  from repository_classification a LEFT JOIN  repository_article b on b.blog_id = a.blog_id and a.nid=b.classification_id_id where a.blog_id =%(n1)d GROUP BY (a.nid)' % {
            "n1": blogInfo.bid}
        category_list = models.Classification.objects.raw(str)
        str = 'select nid, count(nid) as num,strftime("%%Y-%%m",create_time) as ctime from repository_article where blog_id =%(n1)d group by strftime("%%Y-%%m",create_time)' % {
            "n1": blogInfo.bid}
        date_list = models.Article.objects.raw(str)
        return render(request, 'Home/home_detail.html',
                      {
                          'blog': blogInfo,
                          'article': article,
                          'comment_list': comment_list,
                          'tag_list': tag_list,
                          'category_list': category_list,
                          'date_list': date_list,
                          'aaron_page': aaron_page,
                      })
    @csrf_exempt
    def PublishComment(request):
        print(1111111111)
        return render(request, "Aaron/1.html", {"res": "评论成功"})
    home
    {% extends 'Home/home_layout.html' %}
    
    {% block css %}
        <link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.min.css"/>
        <script src="/static/plugins/kindeditor/kindeditor-all.js"></script>
         <script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
    {% endblock %}
    
    {% block content %}
        {% csrf_token %}
        <div class="art-title">
            <a>{{ article.title }}</a>
        </div>
        <div class="art-content">
            {{ article.article_detail.detail|safe }}
        </div>
        <div class="art-recommend clearfix">
              <div class="recommend">
                <a href="#" class="up"
                   style="margin: 5px 10px;display: inline-block;padding: 5px 15px;border: 1px solid #dddddd;text-align: center;">
                    <i class="fa fa-thumbs-o-up" aria-hidden="true" style="font-size: 25px"></i>
                    <div>{{ article.up_count }}</div>
                </a>
                <a href="#" class="down"
                   style="margin: 5px 30px 5px 10px;display: inline-block;padding: 5px 15px;border: 1px solid #dddddd;text-align: center;">
                    <i class="fa fa-thumbs-o-down fa-3" aria-hidden="true" style="font-size: 25px"></i>
                    <div>{{ article.down_count }}</div>
                </a>
            </div>
        </div>
        <div class="art-tips clearfix">
            <div class="tips">
                <span class="ctime">{{ article.create_time }}</span>
                <a class="author">{{ blog.user.username}}</a>
                <span class="comment-count">评论({{ article.comment_count }})</span>
                <span class="read-count">阅读({{ article.read_count }})</span>
            </div>
        </div>
        <div id="AllanboltSignature">
            <div style="border-bottom: #e0e0e0 1px dashed; border-left: #e0e0e0 1px dashed; padding: 10px; font-family: 微软雅黑; font-size: 11px; border-top: #e0e0e0 1px dashed; border-right: #e0e0e0 1px dashed; "
                 id="PSignature">
                <div style="float:left;70px;">
                    <img src="/static/imgs/o_Warning.png" style="65px;height:65px">
                </div>
                <div style="float:left;padding-top:10px;">
    
                    <div style="padding: 1px">作者:<a href="http://www.cnblogs.com/wupeiqi/"
                                                    target="_blank">{{ blog.user.username }}</a></div>
                    <div style="padding: 1px">出处:<a href="http://www.cnblogs.com/wupeiqi/" target="_blank">http://www.cnblogs.com/{{ blog.site }}.html/</a>
                    </div>
                    <div style="padding: 1px">本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接</div>
                </div>
                <div style="clear:both;"></div>
            </div>
        </div>
        <div class="art-comment">
            <div class="comment-title">
                评论列表
            </div>
            <div class="comment-list">
                {% for comment in comment_list %}
                <div class="comment-item">
                    <div class="reply-title clearfix">
                        <div class="user-info">
                            <span>{{ comment.user.username }}</span>
                            <span>{{ comment.create_time }}</span>
                        </div>
                        <div class="reply">
                            <a href="#">回复</a>
                        </div>
                    </div>
                    <div class="reply-body">
                        {% if comment.reply %}
                        <div class="reply-user">@{{ comment.reply.user.username }}</div>
                        {% endif %}
                        <div class="content">
                            {{ comment.comment }}
                        </div>
                    </div>
                </div>
                {% endfor %}
            </div>
    
            <div class="comment-list-pager">
               <ul class="pagination pagination-sm">
                    {{ aaron_page.page_str|safe }}
                </ul>
            </div>
    
            <div class="comment-area">
                <div class="replay-comment-user"></div>
                <div class="reply-area" style="position: relative;">
                    {% if not request.user %}
                    <div style="text-align:center;line-height:200px;position: absolute;top:0;left:0;right:0;bottom: 0;background-color: rgba(255,255,255,.6)">
                        您需要登录后才可以回帖 <a href="/login.html">登录</a> | <a href="/register.html">立即注册</a>
                    </div>
                    {% endif %}
                     <textarea name="content" style=" 100%;height:200px;visibility:hidden;"></textarea>
                </div>
                <div>
                    <div class="reply-btn">
                        <span><span>25</span>/255字</span>
                        <a class="btn btn-primary" onclick="PublishComment()">发表回复</a>
                    </div>
                </div>
            </div>
        </div>
    {% endblock %}
    
    {% block js %}
            <script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
            <script>
        var editor;
        KindEditor.ready(function (K) {
            editor = K.create('textarea[name="content"]', {
                resizeType: 1,
                allowPreviewEmoticons: false,
                allowImageUpload: false,
                items: [
                    'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', 'italic', 'underline',
                    'removeformat', '|', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist',
                    'insertunorderedlist', '|', 'emoticons', 'image', 'link']
            });
        });
    
        function PublishComment(){
            var st = "123";
             $.ajaxSetup({
                data: {csrfmiddlewaretoken: '{{ csrf_token }}'},
            });
            $.ajax({
                url: 'PublishComment.html',
                type: 'POST',
                dataType: 'json',
                data: {"ajaxTest": st},
                success: function (arg) {
                    alert(arg)
                }
            })
        }
    
    
    
    </script>
    {% endblock %}
    View Code

  • 相关阅读:
    权限框架之Shiro详解(非原创)
    MySQL数据库基础详解(非原创)
    ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第十四天(非原创)
    ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第十三天(非原创)
    nginx配置location与rewrite规则教程
    CentOS7安装MySQL 5.7
    MySQL 5.6 解决InnoDB: Error: Table "mysql"."innodb_table_stats" not found.问题
    公文流转系统(未完成)
    对java异常的总结及java项目中的常用的异常处理情况
    课堂动手动脑验证以及自定义异常类实现对异常处理——java异常类
  • 原文地址:https://www.cnblogs.com/YK2012/p/10354134.html
Copyright © 2011-2022 走看看