后台登录

后台登录

后端开发准备工作

1.配置好数据库
2.配置好模板文件的路径
3.配置好静态文件的路径
4.配置好时区
5.配置模板的static过滤器

1.配置好数据库

使用Navicat Premium创建数据库

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "xfz",
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': 'root'
    }
}

2.配置好模板文件的路径.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates', 
        'DIRS': [os.path.join(BASE_DIR, 'front','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',
            ],
            'builtins':[
                'django.templatetags.static'
            ]
        },
    },
]

3.配置好静态文件的路径

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'front','dist')
]

4.配置好时区

TIME_ZONE = 'Asia/Shanghai'

5.配置模板的static过滤器

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates', 
        'DIRS': [os.path.join(BASE_DIR, 'front','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',
            ],
            'builtins':[
                'django.templatetags.static'  // 配置模板的static过滤器
            ]
        },
    },
]

测试代码

#encoding: utf-8
from django.urls import path
from . import views

app_name = 'news'

urlpatterns = [
       path('',views.index,name='index')
]
from django.shortcuts import render
def index(request):
    return render(request,'news/index.html')

from django.urls import path,include


urlpatterns = [
    path('',include("apps.news.urls"))]

<head>
    <meta charset="UTF-8">
    <title>知了课堂</title>
    <link rel="stylesheet" href="{% static 'css/news/index.min.css'%}">
    <link rel="stylesheet" href="//at.alicdn.com/t/font_681895_w5poic4qj6vfgvi.css">
    <script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
    <script src="{% static 'js/index.min.js' %}"></script>
</head>

adminlte框架集成和登录页面实现

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>CMS后台管理系统|登录</title>
  <!-- Tell the browser to be responsive to screen width -->
  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
  <!-- Bootstrap 3.3.7 -->
  <link rel="stylesheet" href="{% static 'adminlte/bower_components/bootstrap/dist/css/bootstrap.min.css' %}">
  <!-- Font Awesome -->
  <link rel="stylesheet" href="{% static 'adminlte/bower_components/font-awesome/css/font-awesome.min.css' %}">
  <!-- Ionicons -->
  <link rel="stylesheet" href="{% static 'adminlte/bower_components/Ionicons/css/ionicons.min.css' %}">
  <!-- Theme style -->
  <link rel="stylesheet" href="{% static 'adminlte/dist/css/AdminLTE.min.css' %}">
  <!-- iCheck -->
  <link rel="stylesheet" href="{% static 'adminlte/plugins/iCheck/square/blue.css' %}">

  <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
  <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
  <!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  <![endif]-->

  <!-- Google Font -->
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
</head>
<body class="hold-transition login-page">
<div class="login-box">
  <div class="login-logo">
    <a href="{% url 'cms:login' %}">CMS管理系统</a>
  </div>
  <!-- /.login-logo -->
  <div class="login-box-body">
    <p class="login-box-msg">请登录</p>

    <form action="" method="post">
      <div class="form-group has-feedback">
        <input type="email" class="form-control" placeholder="邮箱">
        <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
      </div>
      <div class="form-group has-feedback">
        <input type="password" class="form-control" placeholder="密码">
        <span class="glyphicon glyphicon-lock form-control-feedback"></span>
      </div>
      <div class="row">
        <div class="col-xs-8">
          <div class="checkbox icheck">
            <label>
              <input type="checkbox"> 记住我
            </label>
          </div>
        </div>
        <!-- /.col -->
        <div class="col-xs-4">
          <button type="submit" class="btn btn-primary btn-block btn-flat">登录</button>
        </div>
        <!-- /.col -->
      </div>
    </form>
  </div>
  <!-- /.login-box-body -->
</div>
<!-- /.login-box -->

<!-- jQuery 3 -->
<script src="{% static 'adminlte/bower_components/jquery/dist/jquery.min.js' %}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{% static 'adminlte/bower_components/bootstrap/dist/js/bootstrap.min.js' %}"></script>
<!-- iCheck -->
<script src="{% static 'adminlte/plugins/iCheck/icheck.min.js' %}"></script>
<script>
  $(function () {
    $('input').iCheck({
      checkboxClass: 'icheckbox_square-blue',
      radioClass: 'iradio_square-blue',
      increaseArea: '20%' /* optional */
    });
  });
</script>
</body>
</html>

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'apps.news',
    'apps.cms'
]
from django.urls import path
from . import views

app_name='cms'

urlpatterns=[
    path('login/',views.login_view,name='login')
]
from django.shortcuts import render

def login_view(request):
    return render(request,'cms/login.html')
urlpatterns = [
    path('cms/', include('apps.cms.urls')),
    path('',include("apps.news.urls")),

]

User模型创建

关于用户系统
1.使用django内置的User系统
2.需要重新定制
3.前后台使用的是同一个User系统

自定义User模型
1.创建一个xfzauth的app,用来管理用户系统
2.全部重写,继承自AbstractBaseUser
3.定义UserManager
4.设置AUTH_USER_MODEL
5.映射到数据库

    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

AUTH_USER_MODEL='xfzauth.User'
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'apps.news',
    'apps.cms',
    'apps.xfzauth'

]
#encoding: utf-8

from django.contrib.auth.models import AbstractBaseUser,PermissionsMixin,BaseUserManager
from shortuuidfield import ShortUUIDField
from django.db import models


class UserManager(BaseUserManager):
    def _create_user(self,telephone,username,password,**kwargs):
        if not telephone:
            raise ValueError('请传入手机号码!')
        if not username:
            raise ValueError('请传入用户名!')
        if not password:
            raise ValueError('请传入密码!')

        user = self.model(telephone=telephone,username=username,**kwargs)
        user.set_password(password)
        user.save()
        return user

    def create_user(self,telephone,username,password,**kwargs):
        kwargs['is_superuser'] = False
        return self._create_user(telephone,username,password,**kwargs)

    def create_superuser(self,telephone,username,password,**kwargs):
        kwargs['is_superuser'] = True
        kwargs['is_staff'] = True
        return self._create_user(telephone,username,password,**kwargs)


class User(AbstractBaseUser,PermissionsMixin):
    # 我们不使用默认的自增长的主键
    # id:100,101,102,103
    # uuid/shortuuid
    # Shortuuidfield:pip install django-shortuuidfield
    uid = ShortUUIDField(primary_key=True)
    telephone = models.CharField(max_length=11,unique=True)
    email = models.EmailField(unique=True,null=True)
    username = models.CharField(max_length=100)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    data_joined = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = 'telephone'
    # telephone,username,password
    REQUIRED_FIELDS = ['username']
    EMAIL_FIELD = 'email'

    objects = UserManager()

    def get_full_name(self):
        return self.username

    def get_short_name(self):
        return self.username

登录功能实现(1)

1.因为共用一个账号,所以只要一个登陆界面
2.因为登陆界面是一个模态对话框,所以走ajax请求
3.把所有的登陆逻辑写在xfzauth这个app

登录功能实现(2)

重构Restful API的实现

#encoding: utf-8
from django.http import JsonResponse

class HttpCode(object):
    ok = 200
    paramserror = 400
    unauth = 401
    methoderror = 405
    servererror = 500

# {"code":400,"message":"","data":{}}
def result(code=HttpCode.ok,message="",data=None,kwargs=None):
    json_dict = {"code":code,"message":message,"data":data}

    if kwargs and isinstance(kwargs,dict) and kwargs.keys():
        json_dict.update(kwargs)

    return JsonResponse(json_dict)


def ok():
    return result()


def params_error(message="",data=None):
    return result(code=HttpCode.paramserror,message=message,data=data)

def unauth(message="",data=None):
    return result(code=HttpCode.unauth,message=message,data=data)

def method_error(message='',data=None):
    return result(code=HttpCode.methoderror,message=message,data=data)

def server_error(message='',data=None):
    return result(code=HttpCode.servererror,message=message,data=data)

将静态页面改造成Django模板(1)

{% extends 'base/front_base.html' %}
{% load news_filters %}

{% block title %}
    小饭桌
{% endblock %}

{% block head %}
    <link rel="stylesheet" href="{% static 'css/news/index.min.css' %}">
    <script src="{% static 'arttemplate/template-web.js' %}"></script>
    <script src="{% static 'js/index.min.js' %}"></script>
<script id="news-item" type="text/html">
{% verbatim %}
{{ each newses news index }}
<li>
    <div class="thumbnail-group">
        <a href="/news/{{ news.id }}/">
            <img src="{{ news.thumbnail }}" alt="">
        </a>
    </div>
    <div class="news-group">
        <p class="title">
            <a href="/news/{{ news.id }}/">{{ news.title }}</a>
        </p>
        <p class="desc">
            {{ news.desc }}
        </p>
        <p class="more">
           <span class="category">{{ news.category.name }}</span>
            <span class="pub-time">{{ news.pub_time|timeSince }}</span>
            <span class="author">{{ news.author.username }}</span>
        </p>
    </div>
</li>
{{ /each }}
{% endverbatim %}
</script>
{% endblock %}

{% block main %}
    <div class="main">
        <div class="wrapper">
            <div class="main-content-wrapper">
                <div class="banner-group" id="banner-group">
                    <ul class="banner-ul" id="banner-ul">
                        {% for banner in banners %}
                            <li>
                                <a href="{{ banner.link_to }}">
                                    <img src="{{ banner.image_url }}" alt="">
                                </a>
                            </li>
                        {% endfor %}
                    </ul>
                    <span class="arrow left-arrow"></span>
                    <span class="arrow right-arrow"></span>
                    <div class="page-control-group">
                        <ul class="page-control">
                        </ul>
                    </div>
                </div>
                <div class="list-outer-group">
                    <ul class="list-tab">
                        <li data-category="0" class="active"><a href="javascript:void(0);">最新资讯</a></li>
                        {% for category in categories %}
                            <li data-category="{{ category.pk }}"><a href="javascript:void(0);">{{ category.name }}</a></li>
                        {% endfor %}
                    </ul>
                    <ul class="list-inner-group">
                        {% for news in newses %}
                            <li>
                            <div class="thumbnail-group">
                                <a href="{% url 'news:news_detail' news_id=news.pk %}">
                                    <img src="{{ news.thumbnail }}" alt="">
                                </a>
                            </div>
                            <div class="news-group">
                                <p class="title">
                                    <a href="{% url 'news:news_detail' news_id=news.pk %}">{{ news.title }}</a>
                                </p>
                                <p class="desc">
                                    {{ news.desc }}
                                </p>
                                <p class="more">
                                   <span class="category">{{ news.category.name }}</span>
                                    <span class="pub-time">{{ news.pub_time|time_since }}</span>
                                    <span class="author">{{ news.author.username }}</span>
                                </p>
                            </div>
                        </li>
                        {% endfor %}
                    </ul>
                    <div class="load-more-group">
                        <button class="load-more" id="load-more-btn">查看更多</button>
                    </div>
                </div>
            </div>
            {% include 'common/sidebar.html' %}
        </div>
    </div>
{% endblock %}
{% extends 'base/front_base.html' %}
{% load news_filters %}

{% block title %}
    新闻详情页
{% endblock %}

{% block head %}
    <link rel="stylesheet" href="{% static 'css/news/news_detail.min.css' %}">
    <script src="{% static 'arttemplate/template-web.js' %}"></script>
    <script src="{% static 'js/news_detail.min.js' %}"></script>
<script id="comment-item" type="text/html">
{% verbatim %}
<li>
    <div class="comment-info">
        <img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1528129845916&di=536993042d5223862f8c4ab157ba6e72&imgtype=0&src=http%3A%2F%2Fpic1.ipadown.com%2Fimgs%2F201206120933354195.jpg" alt="" class="avatar">
        <span class="author">{{ comment.author.username }}</span>
        <span class="pub-time">{{ comment.pub_time|timeSince }}</span>
    </div>
    <p class="comment-content">{{ comment.content }}</p>
</li>
{% endverbatim %}
</script>
{% endblock %}

{% block main %}
    <div class="main">
        <div class="wrapper">
            <div class="main-content-wrapper">
                <div class="news-wrapper">
                    <h1 class="title">{{ news.title }}</h1>
                    <div class="news-info">
                        <div class="info-group">
                            <span class="author">{{ news.author.username }}</span>
                            <span class="pub-time">{{ news.pub_time|time_since }}</span>
                            <span class="category">{{ news.category.name }}</span>
                        </div>
                        <div class="share-group">
                            <span>分享至:</span>
                            <a class="weixin share-item"></a>
                            <a href="#" class="weibo share-item"></a>
                        </div>
                    </div>
                    <article class="article">
                        {{ news.content|safe }}
                    </article>
                </div>
                <div class="comment-wrapper">
                    <h3 class="title">文章评论(0)</h3>
                    <textarea name="comment" class="comment-textarea logined-textarea" placeholder="立即登录,参与评论~"></textarea>
                    <div class="submit-btn-group">
                        <button class="submit-btn" data-news-id="{{ news.pk }}">立即评论</button>
                    </div>
                    <ul class="comment-list">
                        {% for comment in news.comments.all %}
                            <li>
                                <div class="comment-info">
                                    <img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1528129845916&di=536993042d5223862f8c4ab157ba6e72&imgtype=0&src=http%3A%2F%2Fpic1.ipadown.com%2Fimgs%2F201206120933354195.jpg" alt="" class="avatar">
                                    <span class="author">{{ comment.author.username }}</span>
                                    <span class="pub-time">{{ comment.pub_time|time_since }}</span>
                                </div>
                                <p class="comment-content">{{ comment.content }}</p>
                            </li>
                        {% endfor %}
                    </ul>
                </div>
            </div>
            {% include 'common/sidebar.html' %}
        </div>
    </div>
{% endblock %}
<div class="sidebar-wrapper">
                <div class="title-group">
                    <span class="title">在线课堂</span>
                    <a class="more" href="#">更多</a>
                </div>
                <div class="advertise-group">
                    <a href="#">
                        <img src="http://www.xfz.cn/static/build/images/side-gift-banner.png" alt="">
                    </a>
                </div>
                <div class="platform-group">
                    <div class="title-group">
                        <span class="title">关注小饭桌</span>
                    </div>
                    <div class="focus-group">
                        <ul class="left-group">
                           <li class="zhihu">
                               <a href="#" target="_blank">小饭桌创业课堂</a>
                           </li>
                            <li class="weibo">
                               <a href="#" target="_blank">小饭桌创业课堂</a>
                           </li>
                            <li class="toutiao">
                               <a href="#" target="_blank">小饭桌</a>
                           </li>
                        </ul>
                        <div class="right-group">
                            <p class="desc">扫码关注小饭桌微信公众平台xfz008</p>
                        </div>
                    </div>
                </div>
                <div class="hot-news-group">
                    <div class="title-group">
                        <span class="title">热门推荐</span>
                    </div>
                    <ul class="hot-list-group">
                        <li>
                            <div class="left-group">
                                <p class="title">
                                    <a href="#">王健林卖掉进军海外首个项目:17亿售伦敦ON...</a>
                                </p>
                                <p class="more">
                                    <span class="category">深度报道</span>
                                    <span class="pub-time">1小时前</span>
                                </p>
                            </div>
                            <div class="right-group">
                                <a href="#">
                                    <img src="http://static-image.xfz.cn/1516169692_914.jpg-website.news.list" alt="">
                                </a>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
{% extends 'base/front_base.html' %}
{% load news_filters %}

{% block title %}
    搜索
{% endblock %}

{% block head %}
    <link rel="stylesheet" href="{% static 'css/search/search.min.css' %}">
{% endblock %}

{% block main %}
    <div class="main">
        <div class="wrapper">
            <div class="main-content-wrapper">
                <div class="search-group">
                    <form action="" method="get">
                        <input type="text" name="q" class="search-input" placeholder="请输入关键字" value="{{ query }}">
                        <input type="submit" class="search-btn" value="搜索">
                    </form>
                </div>
                <div class="recommend-group">
                    <p class="recommend-title">热门推荐</p>
                    <ul class="recommend-list">
                        {% for result in page.object_list %}
                            {% with result.object as news %}
                                <li>
                                    <div class="thumbnail-group">
                                        <a href="#">
                                            <img src="{{ news.thumbnail }}" alt="">
                                        </a>
                                    </div>
                                    <div class="news-group">
                                        <p class="title">
                                            <a href="#">{{ news.title }}</a>
                                        </p>
                                        <p class="desc">
                                            {{ news.desc }}
                                        </p>
                                        <p class="more">
                                           <span class="category">{{ news.category.name }}</span>
                                            <span class="pub-time">{{ news.pub_time|time_since }}</span>
                                            <span class="author">{{ news.author.username }}</span>
                                        </p>
                                    </div>
                                </li>
                            {% endwith %}
                        {% endfor %}
                    </ul>
                </div>
            </div>
            {% include 'common/sidebar.html' %}
        </div>
    </div>
{% endblock %}

将静态页面改造成Django模板(2)

在这里插入代码片
在这里插入代码片
在这里插入代码片
在这里插入代码片
在这里插入代码片
在这里插入代码片

登录模态对话框和网站的集成

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200203161457653.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzc1MzE4,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200203161518883.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzc1MzE4,size_16,color_FFFFFF,t_70)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>授权页面</title>
    <link rel="stylesheet" href="../../dist/css/common/auth.min.css">
    <link rel="stylesheet" href="//at.alicdn.com/t/font_681895_ufv8ns8pw60z4cxr.css">
    <script src="../../dist/js/jquery-3.3.1.min.js"></script>
    <script src="../../dist/js/auth.min.js"></script>
</head>
<body>
    <button id="btn">登录/注册</button>
    <div class="mask-wrapper">
        <div class="auth-wrapper">
            <div class="close-wrapper">
                <span class="close-btn icon-close iconfont"></span>
            </div>
            <div class="auth-inner-wrapper">
                <div class="scroll-wrapper">
                    <div class="signin-group auth-group">
                        <div class="top-group">
                            <span class="title">请登录</span>
                            <a href="javascript: void(0);" class="switch">立即注册></a>
                        </div>
                        <div class="form-group">
                            <div class="input-group">
                                <input type="text" class="form-control" name="telephone" placeholder="请输入手机号码">
                            </div>
                             <div class="input-group">
                                <input type="password" class="form-control" name="password" placeholder="请输入密码">
                            </div>
                            <div class="input-group">
                                <label class="remember-label">
                                    <input type="checkbox" name="remember" value="1">
                                    记住我
                                </label>
                            </div>
                            <div class="input-group">
                                <input type="submit" class="submit-btn" value="立即登录">
                            </div>
                        </div>
                    </div>
                    <div class="signup-group auth-group">
                        <div class="top-group">
                            <span class="title">请注册</span>
                            <a href="javascript: void(0);" class="switch">立即登录></a>
                        </div>
                        <div class="form-group">
                            <div class="input-group">
                                <input type="text" class="form-control" name="telephone" placeholder="手机号码">
                            </div>
                            <div class="input-group">
                                <input type="text" class="form-control" name="username" placeholder="用户名">
                            </div>
                            <div class="input-group">
                                <div class="short-input-group">
                                    <input type="text" class="form-control" name="img_captcha" placeholder="图形验证码">
                                </div>
                                <div class="input-group-addon">
                                    <img src="" alt="">
                                </div>
                            </div>
                            <div class="input-group">
                                <input type="text" class="form-control" name="password1" placeholder="密码">
                            </div>
                            <div class="input-group">
                                <input type="text" class="form-control" name="password2" placeholder="确认密码">
                            </div>
                            <div class="input-group">
                                <div class="short-input-group">
                                    <input type="text" class="form-control" name="sms_captcha" placeholder="短信验证码">
                                </div>
                                <div class="input-group-addon">
                                    <span class="sms-captcha-btn">发送验证码</span>
                                </div>
                            </div>
                            <div class="input-group">
                                <input type="submit" class="submit-btn" value="立即注册">
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>
//
// // 点击登录按钮,弹出模态对话框
// $(function () {
//     $("#btn").click(function () {
//         $(".mask-wrapper").show();
//     });
//
//     $(".close-btn").click(function () {
//         $(".mask-wrapper").hide();
//     });
// });
//
//
// $(function () {
//     $(".switch").click(function () {
//         var scrollWrapper = $(".scroll-wrapper");
//         var currentLeft = scrollWrapper.css("left");
//         currentLeft = parseInt(currentLeft);
//         if(currentLeft < 0){
//             scrollWrapper.animate({"left":'0'});
//         }else{
//             scrollWrapper.animate({"left":"-400px"});
//         }
//     });
// });

function Auth() {
    var self = this;
    self.maskWrapper = $('.mask-wrapper');
    self.scrollWrapper = $(".scroll-wrapper");
}

Auth.prototype.run = function () {
    var self = this;
    self.listenShowHideEvent();
    self.listenSwitchEvent();
    self.listenSigninEvent();
};

Auth.prototype.showEvent = function () {
    var self = this;
    self.maskWrapper.show();
};

Auth.prototype.hideEvent = function () {
    var self = this;
    self.maskWrapper.hide();
};

Auth.prototype.listenShowHideEvent = function () {
    var self = this;
    var signinBtn = $('.signin-btn');
    var signupBtn = $('.signup-btn');
    var closeBtn = $('.close-btn');

    signinBtn.click(function () {
        self.showEvent();
        self.scrollWrapper.css({"left":0});
    });

    signupBtn.click(function () {
        self.showEvent();
        self.scrollWrapper.css({"left":-400});
    });

    closeBtn.click(function () {
        self.hideEvent();
    });
};

Auth.prototype.listenSwitchEvent = function () {
    var self = this;
    var switcher = $(".switch");
    switcher.click(function () {
        var currentLeft = self.scrollWrapper.css("left");
        currentLeft = parseInt(currentLeft);
        if(currentLeft < 0){
            self.scrollWrapper.animate({"left":'0'});
        }else{
            self.scrollWrapper.animate({"left":"-400px"});
        }
    });
};

Auth.prototype.listenSigninEvent = function () {
    var self = this;
    var signinGroup = $('.signin-group');
    var telephoneInput = signinGroup.find("input[name='telephone']");
    var passwordInput = signinGroup.find("input[name='password']");
    var rememberInput = signinGroup.find("input[name='remember']");

    var submitBtn = signinGroup.find(".submit-btn");
    submitBtn.click(function () {
        var telephone = telephoneInput.val();
        var password = passwordInput.val();
        var remember = rememberInput.prop("checked");

        xfzajax.post({
            'url': '/account/login/',
            'data': {
                'telephone': telephone,
                'password': password,
                'remember': remember?1:0
            },
            'success': function (result) {
                if(result['code'] == 200){
                    self.hideEvent();
                    window.location.reload();
                }else{
                    var messageObject = result['message'];
                    if(typeof messageObject == 'string' || messageObject.constructor == String){
                        window.messageBox.show(messageObject);
                    }else{
                        // {"password":['密码最大长度不能超过20为!','xxx'],"telephone":['xx','x']}
                        for(var key in messageObject){
                            var messages = messageObject[key];
                            var message = messages[0];
                            window.messageBox.show(message);
                        }
                    }
                }
            },
            'fail': function (error) {
                console.log(error);
            }
        });
    });
};

$(function () {
    var auth = new Auth();
    auth.run();
});

登录功能和模态对话框集成

toast提示错误消息

登录状态更改和退出登录

图形验证码的制作和点击更换

pip install Pillow
# -*- coding: utf-8 -*-
# @Author: huangyong
# @Date:   2016-10-29 22:18:38
# @Last Modified by:   Administrator
# @Last Modified time: 2016-11-21 20:08:31
import random
# pip install Pillow
# Image:是一个画板(context),ImageDraw:是一个画笔, ImageFont:画笔的字体
from PIL import Image,ImageDraw,ImageFont
import time
import os
import string

# Captcha验证码

class Captcha(object):
    # 把一些常量抽取成类属性
    #字体的位置
    font_path = os.path.join(os.path.dirname(__file__),'verdana.ttf')
    # font_path = 'utils/captcha/verdana.ttf'
    #生成几位数的验证码
    number = 4
    #生成验证码图片的宽度和高度
    size = (100,40)
    #背景颜色,默认为白色 RGB(Re,Green,Blue)
    bgcolor = (0,0,0)
    #随机字体颜色
    random.seed(int(time.time()))
    fontcolor = (random.randint(200,255),random.randint(100,255),random.randint(100,255))
    # 验证码字体大小
    fontsize = 20
    #随机干扰线颜色。
    linecolor = (random.randint(0,250),random.randint(0,255),random.randint(0,250))
    # 是否要加入干扰线
    draw_line = True
    # 是否绘制干扰点
    draw_point = True
    # 加入干扰线的条数
    line_number = 3

    SOURCE = list(string.ascii_letters)
    for index in range(0, 10):
        SOURCE.append(str(index))

    #用来随机生成一个字符串(包括英文和数字)
    # 定义成类方法,然后是私有的,对象在外面不能直接调用
    @classmethod
    def gene_text(cls):
        return ''.join(random.sample(cls.SOURCE,cls.number))#number是生成验证码的位数

    #用来绘制干扰线
    @classmethod
    def __gene_line(cls,draw,width,height):
        begin = (random.randint(0, width), random.randint(0, height))
        end = (random.randint(0, width), random.randint(0, height))
        draw.line([begin, end], fill = cls.linecolor)

    # 用来绘制干扰点
    @classmethod
    def __gene_points(cls,draw,point_chance,width,height):
        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))

    #生成验证码
    @classmethod
    def gene_code(cls):
        width,height = cls.size #宽和高
        image = Image.new('RGBA',(width,height),cls.bgcolor) #创建画板
        font = ImageFont.truetype(cls.font_path,cls.fontsize) #验证码的字体
        draw = ImageDraw.Draw(image)  #创建画笔
        text = cls.gene_text() #生成字符串
        font_width, font_height = font.getsize(text)
        draw.text(((width - font_width) / 2, (height - font_height) / 2),text,font= font,fill=cls.fontcolor) #填充字符串
        # 如果需要绘制干扰线
        if cls.draw_line:
            # 遍历line_number次,就是画line_number根线条
            for x in range(0,cls.line_number):
                cls.__gene_line(draw,width,height)
        # 如果需要绘制噪点
        if cls.draw_point:
            cls.__gene_points(draw,10,width,height)

        return (text,image)

短信验证码的发送

注册短信API:聚合网站:https://www.juhe.cn/

pip install requests
#encoding: utf-8

import requests


def send(mobile,captcha):
    url = "http://v.juhe.cn/sms/send"
    params = {
        "mobile": mobile,
        "tpl_id": "121674",
        "tpl_value": "#code#="+captcha,
        "key": "4f2dc49ce16b8538522f0f11fb6cd0a2"
    }
    response = requests.get(url,params=params)
    result = response.json()
    if result['error_code'] == 0:
        return True
    else:
        return False
def sms_captcha(request):
    # /sms_captcha/?telephone=xxx
    telephone = request.GET.get('telephone')
    code = Captcha.gene_text()
    cache.set(telephone,code,5*60)
    print('短信验证码:',code)
    # result = aliyunsms.send_sms(telephone,code)
    result = smssender.send(telephone,code)
    if result:
        return restful.ok()
    else:
        return result.params_error(message="短信验证码发送失败!")

django项目中集成短信验证码发送

短信验证码与注册页面的集成

memcached存储验证码

        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

AUTH_USER_MODEL='xfzauth.User'

# 缓存配置
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211'
    }
}

在这里插入图片描述

注册功能后台代码完成

#encoding: utf-8
from django import forms
from apps.forms import FormMixin
from django.core.cache import cache
from .models import User

class LoginForm(forms.Form,FormMixin):
    telephone = forms.CharField(max_length=11)
    password = forms.CharField(max_length=20,min_length=6,error_messages={"max_length":"密码最多不能超过20个字符!","min_length":"密码最少不能少于6个字符!"})
    remember = forms.IntegerField(required=False)


class RegisterForm(forms.Form,FormMixin):
    telephone = forms.CharField(max_length=11)
    username = forms.CharField(max_length=20)
    password1 = forms.CharField(max_length=20, min_length=6,
                               error_messages={"max_length": "密码最多不能超过20个字符!", "min_length": "密码最少不能少于6个字符!"})
    password2 = forms.CharField(max_length=20, min_length=6,
                                error_messages={"max_length": "密码最多不能超过20个字符!", "min_length": "密码最少不能少于6个字符!"})
    img_captcha = forms.CharField(min_length=4,max_length=4)
    sms_captcha = forms.CharField(min_length=4,max_length=4)

    def clean(self):
        cleaned_data = super(RegisterForm, self).clean()

        password1 = cleaned_data.get('password1')
        password2 = cleaned_data.get('password2')

        if password1 != password2:
            raise forms.ValidationError('两次密码输入不一致!')

        img_captcha = cleaned_data.get('img_captcha')
        cached_img_captcha = cache.get(img_captcha.lower())
        if not cached_img_captcha or cached_img_captcha.lower() != img_captcha.lower():
            raise forms.ValidationError("图形验证码错误!")

        telephone = cleaned_data.get('telephone')
        sms_captcha = cleaned_data.get('sms_captcha')
        cached_sms_captcha = cache.get(telephone)

        if not cached_sms_captcha or cached_sms_captcha.lower() != sms_captcha.lower():
            raise forms.ValidationError('短信验证码错误!')

        exists = User.objects.filter(telephone=telephone).exists()
        if exists:
            forms.ValidationError('该手机号码已经被注册!')

        return cleaned_data
def register(request):
    form = RegisterForm(request.POST)
    if form.is_valid():
        telephone = form.cleaned_data.get('telephone')
        username = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password1')
        user = User.objects.create_user(telephone=telephone,username=username,password=password)
        login(request,user)
        return restful.ok()
    else:
        print(form.get_errors())
        return restful.params_error(message=form.get_errors())


def img_captcha(request):
    text,image = Captcha.gene_code()
    # BytesIO:相当于一个管道,用来存储图片的流数据
    out = BytesIO()
    # 调用image的save方法,将这个image对象保存到BytesIO中
    image.save(out,'png')
    # 将BytesIO的文件指针移动到最开始的位置
    out.seek(0)

    response = HttpResponse(content_type='image/png')
    # 从BytesIO的管道中,读取出图片数据,保存到response对象上
    response.write(out.read())
    response['Content-length'] = out.tell()

    # 12Df:12Df.lower()
    cache.set(text.lower(),text.lower(),5*60)

    return response


def sms_captcha(request):
    # /sms_captcha/?telephone=xxx
    telephone = request.GET.get('telephone')
    code = Captcha.gene_text()
    cache.set(telephone,code,5*60)
    print('短信验证码:',code)
    # result = aliyunsms.send_sms(telephone,code)
    result = smssender.send(telephone,code)
    if result:
        return restful.ok()
    else:
        return result.params_error(message="短信验证码发送失败!")


def cache_test(request):
    cache.set('username','zhiliao',60)
    result = cache.get('username')
    print(result)
    return HttpResponse('success')

注册页面前端逻辑完成

Auth.prototype.listenSignupEvent = function () {
    var signupGroup = $('.signup-group');
    var submitBtn = signupGroup.find('.submit-btn');
    submitBtn.click(function (event) {
        event.preventDefault();
        var telephoneInput = signupGroup.find("input[name='telephone']");
        var usernameInput = signupGroup.find("input[name='username']");
        var imgCaptchaInput = signupGroup.find("input[name='img_captcha']");
        var password1Input = signupGroup.find("input[name='password1']");
        var password2Input = signupGroup.find("input[name='password2']");
        var smsCaptchaInput = signupGroup.find("input[name='sms_captcha']");

        var telephone = telephoneInput.val();
        var username = usernameInput.val();
        var img_captcha = imgCaptchaInput.val();
        var password1 = password1Input.val();
        var password2 = password2Input.val();
        var sms_captcha = smsCaptchaInput.val();

        xfzajax.post({
            'url': '/account/register/',
            'data': {
                'telephone': telephone,
                'username': username,
                'img_captcha': img_captcha,
                'password1': password1,
                'password2': password2,
                'sms_captcha': sms_captcha
            },
            'success': function (result) {
                window.location.reload();
            }
        });
    });
};

var xfzajax = {
    'get': function (args) {
        args['method'] = 'get';
        this.ajax(args);
    },
    'post': function (args) {
        args['method'] = 'post';
        this._ajaxSetup();
        this.ajax(args);
    },
    'ajax': function (args) {
        var success = args['success'];
        args['success'] = function (result) {
            if(result['code'] === 200){
                if(success){
                    success(result);
                }
            }else{
                var messageObject = result['message'];
                if(typeof messageObject == 'string' || messageObject.constructor == String){
                    window.messageBox.showError(messageObject);
                }else{
                    // {"password":['密码最大长度不能超过20为!','xxx'],"telephone":['xx','x']}
                    for(var key in messageObject){
                        var messages = messageObject[key];
                        var message = messages[0];
                        window.messageBox.showError(message);
                    }
                }
                if(success){
                    success(result);
                }
            }
        };
        args['fail'] = function (error) {
            console.log(error);
            window.messageBox.showError('服务器内部错误!');
        };
        $.ajax(args);
    },
    '_ajaxSetup': function () {
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
                }
            }
        });
    }
};

CMS管理系统访问和限制

                    <div class="user-more-box">
                        <i class="triangle"></i>
                        {% if user.is_staff %}
                            <a href="{% url 'cms:index' %}">管理系统</a>
                        {% endif %}
                        <a href="{% url 'xfzauth:logout' %}">退出登录</a>
                    </div>
@staff_member_required(login_url='index')
def index(request):
    return render(request,'cms/index.html')

CMS管理页面主框架搭建

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>{% block title %}{% endblock %} | 管理系统</title>
    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
    <link rel="stylesheet" href="{% static 'adminlte/bower_components/bootstrap/dist/css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'adminlte/bower_components/font-awesome/css/font-awesome.min.css' %}">
    <link rel="stylesheet" href="{% static 'adminlte/dist/css/AdminLTE.min.css' %}">
    <link rel="stylesheet" href="{% static 'adminlte/dist/css/skins/_all-skins.min.css' %}">
    <link rel="stylesheet" href="{% static 'adminlte/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.min.css' %}">
    <link rel="stylesheet" href="{% static 'sweetalert/sweetalert.css' %}">
    <script src="{% static 'adminlte/bower_components/jquery/dist/jquery.min.js' %}"></script>
    <script src="{% static 'adminlte/bower_components/bootstrap/dist/js/bootstrap.min.js' %}"></script>
    <script src="{% static 'adminlte/dist/js/adminlte.min.js' %}"></script>
    <script src="{% static 'sweetalert/sweetalert.min.js' %}"></script>
    <script src="{% static 'js/xfzajax.min.js' %}"></script>
    <script src="{% static 'js/xfzalert.min.js' %}"></script>
    <script src="{% static 'js/message.min.js' %}"></script>
    {% block head %}{% endblock %}
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
    <header class="main-header">
        <!-- Logo -->
        <a href="/" class="logo">
            <!-- mini logo for sidebar mini 50x50 pixels -->
            <span class="logo-mini"><b>CMS</b></span>
            <!-- logo for regular state and mobile devices -->
            <span class="logo-lg">后台管理系统</span>
        </a>
        <!-- Header Navbar: style can be found in header.less -->
        <nav class="navbar navbar-static-top">
            <!-- Sidebar toggle button-->
            <a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
                <span class="sr-only">Toggle navigation</span>
            </a>

            <div class="navbar-custom-menu">
                <ul class="nav navbar-nav">
                    <li class="dropdown user user-menu">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                            <img src="http://edu-image.nosdn.127.net/4B9BE586B1F982317B930C2C2E6F702D.png"
                                 class="user-image" alt="User Image">
                            <span class="hidden-xs"></span>
                        </a>
                        <ul class="dropdown-menu">
                            <!-- User image -->
                            <li class="user-header">
                                <img src="http://edu-image.nosdn.127.net/4B9BE586B1F982317B930C2C2E6F702D.png"
                                     class="img-circle" alt="User Image">
                                <p>
                                
                                    <small>Python web开发工程师</small>
                                </p>
                            </li>
                            <!-- Menu Footer-->
                            <li class="user-footer">
                                <div class="pull-left">
                                    <a href="#" class="btn btn-default btn-flat">个人中心</a>
                                </div>
                                <div class="pull-right">
                                    <a href="#" class="btn btn-default btn-flat">退出登录</a>
                                </div>
                            </li>
                        </ul>
                    </li>
                </ul>
            </div>
        </nav>
    </header>
    <aside class="main-sidebar">
        <!-- sidebar: style can be found in sidebar.less -->
        <section class="sidebar">
            <form action="#" method="get" class="sidebar-form">
                <div class="input-group">
                    <input type="text" name="q" class="form-control" placeholder="首页">
                    <span class="input-group-btn">
                <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
                </button>
          </span>
                </div>
            </form>
            <!-- /.search form -->
            <!-- sidebar menu: : style can be found in sidebar.less -->
            <ul class="sidebar-menu" data-widget="tree">
                <li class="active">
                    <a href="{% url 'cms:index' %}">
                        <i class="fa fa-home"></i>
                        <span>首页</span>
                    </a>
                </li>
                {% if perms.news.change_news %}
                    <li class="header">新闻管理</li>
                    <li>
                        <a href="{% url 'cms:news_list' %}">
                            <i class="fa fa-list"></i>
                            <span>新闻列表</span>
                        </a>
                    </li>
                    <li>
                        <a href="{% url 'cms:write_news' %}">
                            <i class="fa fa-edit"></i>
                            <span>发布新闻</span>
                        </a>
                    </li>
                    <li>
                        <a href="{% url 'cms:news_category' %}">
                            <i class="fa fa-tag"></i>
                            <span>新闻分类</span>
                        </a>
                    </li>
                    <li>
                        <a href="{% url 'cms:banners' %}">
                            <i class="fa fa-window-restore"></i>
                            <span>轮播图</span>
                        </a>
                    </li>
                {% endif %}
                {% if perms.course.change_course %}
                    <li class="header">课程管理</li>
                    <li>
                        <a href="{% url 'cms:pub_course' %}">
                            <i class="fa fa-tv"></i>
                            <span>发布课程</span>
                        </a>
                    </li>
                {% endif %}
                {% if user.is_superuser %}
                    <li class="header">员工管理</li>
                    <li>
                        <a href="{% url 'cms:staffs' %}">
                            <i class="fa fa-group"></i>
                            <span>员工管理</span>
                        </a>
                    </li>
                {% endif %}
            </ul>
        </section>
    </aside>
    <div class="content-wrapper">
        <section class="content-header">
            {% block content-header %}{% endblock %}
        </section>
        <section class="content">
            {% block content %}{% endblock %}
        </section>
    </div>
    <footer class="main-footer">
        <strong></strong>后台管理系统
    </footer>
</div>
</body>
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值