1创建新项目的准备工作
1.1命令框内创建新项目
打开指定文件夹,在路径位置输入cmd打开命令行
django-admin startproject 项目名 创建项目
1.2在新项目内创建子应用
python manage.py startapp 子应用名
1.3在settings.py文件内注册
在settings.py文件内注册子应用
跨域也顺便弄好
认证模型类也弄好
DRF工程
下载第三方模块
在黑窗口内进行安装
pip install djangorestframework
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders', #配置跨域
'rest_framework', #配置drf框架
'创建的子应用名' #注册子应用
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware' # 添加跨域中间件
]
CORS_ORIGIN_WHITELIST=[
'http://127.0.0.1:8080',
'http://localhost:8080'
]
CORS_ALLOW_CREDENTIALS=True
CORS_ALLOW_METHODS=('*')
CORS_ALLOW_HEADERS=('*')
#用户认证模型类
AUTH_USER_MODEL='子应用名.模型类名'
1.5配置数据库
在settings.py文件内
# 配置数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 使用mysql数据库
'HOST': 'localhost', # 主机
'PORT': 3306, # 端口
'USER': 'root', # 数据库的用户名
'PASSWORD': '密码', # 数据库的密码
'NAME': '创建的数据库名', # 数据库的名字
}
}
1.6修改语言和时区
在settings.py文件内
LANGUAGE_CODE = 'zh-Hans' #语言
TIME_ZONE = 'Asia/Shanghai' #时区
1.7安装数据库
在跟项目名同名的文件夹内init.py文件里安装
import pymysql
pymysql.install_as_MySQLdb()
1.8创建模型类
在子应用文件夹里的models.py创建
from django.db import models
# Create your models here.
#user
from django.contrib.auth.models import AbstractUser
from django.utils import timezone
class User(AbstractUser):
mobile=models.CharField('手机号',max_length=11)
last_login = models.DateTimeField('上次登录时间',default=timezone.now)
def __str__(self):
return self.username
class Meta:
db_table='user'
1.9创建好模型类后进行迁移
在项目内终端执行
生成迁移文件:python manage.py makemigrations
执行迁移:python manage.py migrate
如果迁移出错,把数据库删了创建新的数据库,生成的迁移文件也删了,重新执行上面2个步骤
认证模型类
在settings.py文件内注册
#用户认证模型类
AUTH_USER_MODEL='users.User'
登录后端接口 实现
登录接口
api: /users/logincount/
method: POST
data:
{
username: this.username,
password: this.password,
mobile: this.phone,
code: this.smscode
}
响应:
code == “204” 验证码过期或者错误
code == “205” 用户名或密码错误
code == “206” 没有管理员权限
code == “207” 密码已重置
code == “200” 登录成功, 进入首页
code == “201” 注册成功,需申请管理员权限 后台superuser
必须是管理员才可以登录,即is_staff=True & is_active=True;这些可以使用superuser在后台修改!!!
登录的逻辑:
- 用户第一次登录,使用手机验证码进行注册
存储用户名、密码、手机号,返回201 - 用户第 二 次及 n 次登录,优先使用密码验证;
用户名、密码均正确,检查用户是否有管理员权限(只有is_staff=True&is_active=True时,才允许登录),分别返回响应; - 用户、密码验证未通过时,检查是否有短信验证码,有则验证短信验证码(验证通过则重置密码,返回207);
无短信验证码,直接返回205
编写视图
from rest_framework.views import APIView
from rest_framework.response import Response
from users.models import User
import random,redis
#登录的视图LoginAPIView
from django.contrib.auth.hashers import check_password
from datetime import datetime
from rest_framework_jwt.utils import jwt_encode_handler,jwt_payload_handler
class LoginAPIView(APIView):
def post(self,request):
#1.获取前段数据
username=request.data.get('username')
password=request.data.get('password')
mobile=request.data.get('mobile')
smsCode=request.data.get('smsCode')
#2.判断是不是新用户,
user=User.objects.filter(username=username).first()
redis_conn=redis.Redis(host='127.0.0.1',port=6379,password='shayebushi')
if user:
#该用户是第二次或第n次登录,优先使用密码认证,密码错误再考虑短信
if check_password(password,user.password):
#密码正确,判断密码是否是管理员
if user.is_staff and user.is_active:
#允许成功登录
token=self.gen_token(user)
user.last_login=datetime.now()
user.save()
return Response({
'code':200,
'msg':'登陆成功,进入首页',
'data':{
'uid': user.id,
'username': user.username,
'token': token
}
})
else:
return Response({
'code':206,
'msg':'没有管理员权限'
})
else:
#密码不正确,考虑有没有短信验证码,若有smsCode属于密码重置
if smsCode:
#前端传入短信验证码,密码重置
validation=self.validate_sms_code(smsCode,mobile,redis_conn)
if validation:
#完成短信认证,开始重写密码
user.set_password(password)
user.save()
return Response({
'code':207,
'msg':'密码已重置'
})
else:
return Response({
'code':204,
'msg':'验证码已过期或错误'
})
else:
return Response({
'code':205,
'msg':'用户名或密码错误'
})
else:
#用户第一次来注册,需要使用短信验证码来认证
if smsCode:
#使用验证码验证 并注册
validation=self.validate_sms_code(smsCode,mobile,redis_conn)
if validation:
#注册用户信息
User.objects.create_user(username=username,password=password,mobile=mobile)
return Response({
'code':201,
'msg':'注册成功需要申请管理员权限'
})
else:
return Response({
'code':204,
'msg':'验证码过期或错误'
})
else:
return Response({
'code':208,
'msg':'第一次登录需使用收集验证码'
})
@staticmethod
def gen_token(user):
'''
:param user: 用户对象
:return: jwt token 字符串
'''
#生成payload载荷信息
payload=jwt_payload_handler(user)
# 生成token
token=jwt_encode_handler(payload)
return token
@staticmethod
def validate_sms_code(smsCode,mobile,redis_sonn):
'''
:param smsCode: 短信验证码 字符串
:param mobile: 手机号 字符串
:param redis_sonn: redis 链接对象
:return: Boolean
'''
#构造key
key='sms_%s'%mobile
#获取redis中的验证码
stored_code=redis_sonn.get(key)
#开始对比
if stored_code and stored_code.decode()==smsCode:
return True
else:
return False
配置路由
from django.urls import path
from users import views
urlpatterns = [
#获取短信验证码
path('sms_code/',views.SmsCodeAPIView.as_view()),
# 用户的登录
path('logincount/',views.LoginAPIView.as_view())
]
登录用户信息 前端页面实现
<script>
import cons from "@/components/constant";
export default {
name: "Login",
data() {
return {
errshow: false,
errmsg: "",
password: "",
username: "",
phone: "",
smsCode: "",
};
},
methods: {
// 获取短信验证码
getSmsCode() {
if (!this.phone){
this.$message({
type:'warning',
message:'手机号不能为空'
})
return
}
// 一般要加正则匹配
// 发送短信获取验证码
this.axios.get('/v1/users/sms_code/',{
params:{
mobile:this.phone
}
}).then((result) => {
if (result.data.code==200){
this.$message({
type:'success',
message:result.data.msg
})
}else{
this.$message({
type:'error',
message:result.data.msg
})
}
}).catch((err) => {
console.log('获取短信验证码错误',err)
});
},
// 登录
fnLogin() {
if (this.username == "" || this.password == "") {
this.errmsg = "用户名或密码不能为空";
this.errshow = true;
return;
}
//http://www.meiduo.site:8000/meiduo_admin/authorizations/
// 发送请求
this.axios.post('/v1/users/logincount/',{
username:this.username,
password:this.password,
mobile:this.phone,
smsCode:this.smsCode
}).then((result) => {
console.log('登录的响应:',result)
// 处理响应
if (result.data.code==200){
this.$message({
type:"success",
message:result.data.msg
})
// 保存 useranme uid token
localStorage.clear()
localStorage.token=result.data.data.token
localStorage.uid=result.data.data.uid
localStorage.username=result.data.data.username
// 进入项目的首页
this.$router.push({path:'/home'})
}else{
this.errshow=true
this.errmsg=result.data.msg
}
}).catch((err) => {
console.log('登录错误:',err)
});
},
},
};
</script>
axios注意事项
如果请求错误,就去main.js里查看axios是否配置
统计用户总数,日增,日活跃数
后端
需要导包 import time
利用查询,获取相关的数据
#统计用户总数的视图
class TotaCountAPIView(APIView):
def get(self,request):
#统计用户总数
total_count=User.objects.all().count()
return Response({
'code':200,
'total_count':total_count
})
#日增用户的视图
class DayIncrementAPIView(APIView):
def get(self,request):
# 统计日增用户 #需要导包 import time
current_data=time.strftime('%Y-%m-%d') #查询同一天注册的用户
day_increment=User.objects.filter(date_joined__contains=current_data).count()
return Response({
'code':200,
'day_increment':day_increment
})
#统计日活跃用户 视图
class DayLiveAPIView(APIView):
def get(self,request):
# 统计日活跃用户 #需要导包 import time
current_data = time.strftime('%Y-%m-%d')
day_live = User.objects.filter(last_login__contains=current_data).count()
return Response({
'code': 200,
'day_live': day_live
})
配置路由
from django.urls import path
from users import views
urlpatterns = [
#获取短信验证码
path('sms_code/',views.SmsCodeAPIView.as_view()),
# 用户的登录
path('logincount/',views.LoginAPIView.as_view()),
#统计用户总数
path('total_count/',views.TotaCountAPIView.as_view()),
#获取日增用户
path('day_increment/',views.DayIncrementAPIView.as_view()),
#获取日活用户
path('day_live/',views.DayLiveAPIView.as_view()),
]
前端
注意,要找到对应的vue组件,
例如:CountPannel.vue
在组件内需要修改的地方进行修改
<script>
export default {
name: 'CountPannel',
data(){
return {
total_count:0,
day_increment:0,
day_active:0,
day_orders:0
}
},
mounted(){
let token = localStorage.token;
// 获取总人数
this.axios.get('/v1/users/total_count/', {
headers: {
'Authorization': 'JWT ' + token
},
responseType: 'json',
})
.then(res=>{
console.log('统计用户总数的响应',res);
// {code:200,total_count:300}
this.total_count = res.data.total_count;
}).catch(err=>{
console.log(err.response);
if(err.response.status==401){
this.$router.push({path:'/'});
}
});
// 获取日增人数
this.axios.get('/v1/users/day_increment/', {
headers: {
'Authorization': 'JWT ' + token
},
responseType: 'json',
})
.then(res=>{
console.log('获取日增用户的响应',res)
this.day_increment = res.data.day_increment;
}).catch(err=>{
console.log(err);
});
// 获取日活人数
this.axios.get('/v1/users/day_live/', {
headers: {
'Authorization': 'JWT ' + token
},
responseType: 'json',
})
.then(res=>{
console.log('获取日活的用户',res)
this.day_active = res.data.day_live;
}).catch(err=>{
console.log(err);
});
}
</script>