一、redis通用命令
redis默认有16个 数据库(0-15) select 3 切换到数据库3
info 查看redis服务的信息 info replication查看主从复制的状况
keys * 查看所有的key, 生产环境中不使用 可能阻塞redis
查看key的数据类型 type key1
key 是否存在 exists key1
删除一个key del key1
重命名 rename key key1
flushdb # 清空当前数据库
flushall # 清空所有数据库
二、git 常用命令
1.初始化仓库:git init
2.查看状态:git status
3.添加文件:git add 文件名(*指的是全部)
4.配置个人信息:
git config user.name 你的名字
git config user.email 你的邮箱
5.提交代码:git commit -m 版本信息
6.查看日志信息:git log --oneline
7.回退:git reset --hard HEAD/版本号
8.关联远程仓库:git remote add origin ‘码云地址’
9.提交代码到远程仓库:git push -u origin "master"
10.获取远程仓库的代码:git pull origin master
11.分支操作:
#查看分支 git branch
#创建分支 git branch b1
#切换到b1分支 git switch b1
#将b1分支合并到master git switch master git merge b1
项目实战配置文件
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders', # 跨域
'user', # user应用名
'rest_framework', # drf框架
'goods' # goods应用名
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware', # 注册drf 中间件
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware', # 添加跨域中间件
'middleware.middleware.CheckUserMiddleware',
]
CORS_ORIGIN_WHITELIST = [
# 配置ip白名单
'http://127.0.0.1:8080',
'http://localhost:8080'
]
# credentials
# methods
# headers
CORS_ALLOW_CREDENTIALS = True # 配置允许cookie
CORS_ALLOW_METHODS = ['*'] # 允许的请求方式
CORS_ALLOW_HEADERS = ['*'] # 允许的请求头
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 配置mysql数据库
'NAME': 'djangoproject',
'USER':'root',
'PASSWORD':'123',
'HOST':'localhost',
'PORT':3306
}
}
AUTH_USER_MODEL = 'user.User' # 使用自定义 用户模型类 app.模型类
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static')
]
三、django,vue前后端注册代码
1.手机号跟用户名判断是否重复
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
import re
from user.models import User
# Create your views here.
# 用户名
class CheckUsername(APIView):
def get(self,request,username):
# 1.判断用户名格式
# 要求字母开头,中间为字母,数字,下划线,长度5-16
if not re.findall(r'^[a-zA-Z]\w{4,15}$',username):
return Response({
'code':404,
'msg':'用户名格式不正确'
})
# 2.判断用户是否存在
if User.objects.filter(username=username):
return Response({'msg':'用户名重复','code':400})
else:
return Response({'msg':'ok','code':200})
# 手机号
class MobileAPIView(APIView):
def get(self,request,mobile):
# 1. 判断手机号格式是否满足要求
if not re.findall(r'^1[3-9]\d{9}$',mobile):
return Response({
'msg':'手机号格式不正确',
'code':404
})
# 2. 判断手机号是否存在
if User.objects.filter(mobile=mobile):
return Response({
'msg':'手机号重复',
'code':400
})
else:
return Response({
'msg':'ok',
'code':200
})
2.前端用户名手机号,判断密码是否一致请求
// 用户名的校验方法
let validateName = (rule, value, callback) => {
if (!value) {
return callback(new Error("用户名不能为空"));
}
// 用户名以字母开头,长度在5-16之间,允许字母数字下划线
const userNameRule = /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/;
if (userNameRule.test(value)) {
// 前端校验,用户名复合规则
//请求后端, 判断用户名是否重复
this.$axios
.get("/users/check/username/" + value + "/"
)
.then((res) => {
// 200代表用户名不重复,可以注册
console.log("校验用户名是否重复:", res);
if (res.data.code == 200) {
this.$refs.ruleForm.validateField("checkPass");
return callback();
} else {
// 用户名重复或者不符合规则
return callback(new Error(res.data.msg));
}
})
.catch((err) => {
return Promise.reject(err);
});
} else {
// 前端校验,用户名不符合规则
return callback(new Error("字母开头,长度5-16之间,允许字母数字下划线"));
}
};
// 手机号的校验方法
let validateMobile = (rule, value, callback) => {
if (value === "") {
return callback(new Error("请输入手机号"));
}
// 手机号以1开头,第二位3-9之间的数字,长度为11,只允许数字
const mobileRule = /^1[3-9]\d{9}$/;
if (mobileRule.test(value)) {
this.$axios.get("/users/check/mobile/" + this.RegisterUser.mobile + "/")
.then(res=>{
console.log("验证手机号是否可用:", res)
if(res.data.code == 200){
this.$refs.ruleForm.validateField("checkPass");
return callback();
}else{
return callback(new Error(res.data.msg))
}
}).catch(err=>{
return Promise.reject(err)
})
} else {
return callback(new Error("手机号不符合格式"));
}
};
// 密码的校验方法
let validatePass = (rule, value, callback) => {
if (value === "") {
return callback(new Error("请输入密码"));
}
// 密码以字母开头,长度在6-18之间,允许字母数字和下划线
const passwordRule = /^[a-zA-Z]\w{5,17}$/;
if (passwordRule.test(value)) {
this.$refs.ruleForm.validateField("checkPass");
return callback();
} else {
return callback(
new Error("字母开头,长度6-18之间,允许字母数字和下划线")
);
}
};
// 确认密码的校验方法
let validateConfirmPass = (rule, value, callback) => {
if (value === "") {
return callback(new Error("请输入确认密码"));
}
// 校验是否以密码一致
if (this.RegisterUser.pass != "" && value === this.RegisterUser.pass) {
this.$refs.ruleForm.validateField("checkPass");
return callback();
} else {
return callback(new Error("两次输入的密码不一致"));
}
};
3.django后端实现图形验证码及注册功能
# 图形验证码
class ImgCode(APIView):
def get(self,request,uuid):
# 1.生成4位验证码
# string.ascii_letters 随机字母 a-zA-Z
# string.digits 随机数字 0-9
code = ''.join(random.sample(string.ascii_letters+string.digits,4))
# 2.生成图形验证码
cap = ImageCaptcha() # 定义对象
img_code = cap.generate(code) # 生成图形验证码 de 图片
# 3.保存验证码
r = redis.Redis(host='localhost',port=6379,password='password',db=0)
r.set(uuid,code,ex=60)
r.close()
# 4.返回图形验证码,使用httpResponse返回,需要加上数据类型context_type
return HttpResponse(img_code,content_type='image/png')
# 校验图形验证码
class CheckImageCode(APIView):
def post(self,request):
# 1.提取get参数中的uuid和验证码
uuid = request.data.get('imageCodeID')
img_code = request.data.get('imageCode')
# 2.读取redis数据库中的验证码
r = redis.Redis(host='localhost',password='password',port=6379,db=0)
r_code = r.get(uuid).decode()
if not r_code:
return Response({
'msg':'验证码过期',
'code':204
})
# redis数据库中存的是二进制
# lower()都转换为小写
# decode()解码
if img_code.lower() == r_code.lower():
return Response({'msg':'ok','code':200})
else:
return Response({'msg':'验证码错误','code':404})
# 用户注册
class Register(APIView):
def post(self,request):
# 获取前端提交数据
username = request.data.get('userName')
pwd = request.data.get('pwd')
mobile = request.data.get('mobile')
aggree = request.data.get('aggree')
# 2.判断数据是否齐全
if not all([username,pwd,mobile]):
return Response({
'msg':'用户的注册信息不完整',
'code':204
})
# 3.判断是否同意协议
if not aggree:
return Response({
'msg':'用户未同意协议',
'code':204
})
# 4.往数据库中保存数据 create_user是AbstractUser提供的注册方法,会对密码进行加密
User.objects.create_user(username=username,password=pwd,mobile=mobile)
return Response({'msg':'注册成功','code':200})
4.vue前端实现图形验证码及用户注册
// 校验图片验证码
let validateImageCode = (rule, value, callback) => {
if (value === "") {
return callback(new Error("请输入图片验证码"));
}
// 图片验证码是由字母、数字组成,长度为4
const iamgeCodeRule = /^[a-zA-Z0-9]{4}$/;
if (iamgeCodeRule.test(value)) {
this.$axios.post("/users/check_image_code/", {imageCode:this.RegisterUser.imageCode,imageCodeID:this.imageCodeID})
// this.$axios.post("/users/test/", {username:'laufing1', password:"laufing123",mobile:123})
.then(res => {
if(res.data.code == 200){
this.$refs.ruleForm.validateField("checkPass");
return callback();
}else{
return callback(new Error(res.data.msg))
}
}).catch(err => {
return Promise.reject(err)
})
} else {
return callback(new Error("图片验证码不正确!"));
}
};
// 用户注册
Register() {
// 是否同意用户协议
if(!this.aggree){
this.flag = true
return
}
// 已勾选,则不显示提示信息
this.flag = false
// 通过element自定义表单校验规则,校验用户输入的用户信息
this.$refs["ruleForm"].validate((valid) => {
//如果通过校验开始注册
if (valid) {
this.$axios
.post("/users/register/", {
userName: this.RegisterUser.name,
pwd: this.RegisterUser.pass,
mobile: this.RegisterUser.mobile,
aggree: this.aggree,
})
.then((res) => {
// 200代表注册成功,其他的均为失败
if (res.data.code == 200) {
// 隐藏注册组件
this.isRegister = false;
// 弹出通知框提示注册成功信息
this.notifySucceed(res.data.msg);
} else {
// 弹出通知框提示注册失败信息
this.notifyError(res.data.msg);
}
})
.catch((err) => {
return Promise.reject(err);
});
} else {
return false;
}
});
},
四、登录及退出登录
from django.db.models import Q
# 用户登录
class Login(APIView):
def post(self,request):
username = request.data.get('username')
pwd = request.data.get('password')
try:
user = User.objects.get(Q(username=username)|Q(mobile=username))
except Exception as e:
print(e)
return Response({
'msg': '用户名不存在',
'code': 204
})
if not user.check_password(pwd):
return Response({
'msg':'用户名或密码不正确',
'code':204
})
token = generate_jwt_token(user)
return Response({
'msg':'登录成功',
'code':200,
'user':{
'username':user.username,
'uid':user.id
},
'token':token,
})
# jwt token
def generate_jwt_token(user):
payload = {
'id':user.id,
'username':user.username,
'mobile':user.mobile,
'exp':datetime.datetime.now() + datetime.timedelta(seconds=300)
}
# 进行加密,生成 jwt token
token = jwt.encode(payload=payload,key=settings.SECRET_KEY,algorithm='HS256')
# 返回token
return token
// 退出登录
logout() {
// 不显示退出登录框
this.visible = false;
this.$axios.get("/users/exit/").then((res) => {
console.log("@@退出登录的响应:", res);
if (res.data.code == 200) {
// 清空本地登录信息
// localStorage.setItem("user", "");
localStorage.removeItem("user");
localStorage.removeItem("token")
// 清空vuex登录信息
this.setUser("");
this.notifySucceed("成功退出登录");
} else {
console.log("退出请求失败")
}
}).catch(err => {
return Promise.reject(err)
})
},
// 点击登录触发
Login() {
// 通过element自定义表单校验规则,校验用户输入的用户信息
this.$refs["ruleForm"].validate(valid => {
//如果通过校验开始登录
if (valid) {
// 发送ajax
this.$axios.post("/users/login/", {
user: this.LoginUser.name,
pwd: this.LoginUser.pass,
// withCredentials: true,
})
.then(res => {
console.log("@@登录的响应:", res)
// 200代表登录成功,其他的均为失败
if (res.data.code == 200) {
// res.data为后端响应的json
// 隐藏登录组件
this.isLogin = false;
// 登录信息存到本地缓存
let user = JSON.stringify(res.data.user);
console.log("@@user", user)
//要求后台返回什么样的数据?
//{
// "code":200,
// 'msg': "欢迎user",
// "user":{
// userName:"xxx",
// },
//
//}
// 前端存储用户信息,表示登录成功
localStorage.setItem("user", user);
localStorage.setItem("token", res.data.token)
// sessionStorage.setItem("")
// 登录信息存到vuex,控制页面欢迎信息
// console.log("@@res.data.user", res.data.user)
this.setUser(res.data.user);
// 弹出通知框提示登录成功信息
this.notifySucceed(res.data.msg);
} else {//响应不是200
// 清空输入框的校验状态
this.$refs["ruleForm"].resetFields();
// 弹出通知框提示登录失败信息
this.notifyError(res.data.msg);
}
})
.catch(err => {
console.log(err)
return Promise.reject(err);
});
} else {//未通过用户校验
return false;
}
});
}
五、商品模型类
from django.db import models
# 商品类别表Category:类别名 cate_name
class Category(models.Model):
cate_name = models.CharField("类别名",max_length=50)
class Meta:
db_table = 'category'
verbose_name_plural = '商品类别表'
def __str__(self):
return self.cate_name
# 商品信息表Goods:商品名sku_name 价格price 售价selling_price 默认图片img 商品标题title 描述instruction 销量 count 库存stock cate类别**外键** 是否在销售online
class Goods(models.Model):
sku_name = models.CharField("商品名",max_length=100)
price = models.DecimalField("价格",max_digits=9,decimal_places=2)
selling_price = models.DecimalField("售价",max_digits=9,decimal_places=2)
img = models.CharField("默认图片",max_length=200)
title = models.CharField("商品标题",max_length=30,null=True)
instruction = models.TextField("商品的描述信息")
count = models.IntegerField("商品的销售数量",default=0)
stock = models.IntegerField("商品的库存数量",default=0)
cate = models.ForeignKey(Category,on_delete=models.CASCADE,verbose_name='商品类别')
online = models.BooleanField("是否在售",default=True)
class Meta:
db_table = 'goods'
verbose_name_plural = '商品信息'
def __str__(self):
return self.sku_name
# 商品图片表GoodImg: 图片img 图片描述title good外键所属商品
class Goodimg(models.Model):
img = models.CharField(max_length=200,verbose_name='图片')
title = models.CharField("图片描述",max_length=200,null=True)
good = models.ForeignKey(to=Goods,on_delete=models.CASCADE,verbose_name='所属商品')
class Meta:
db_table = 'goodimg'
verbose_name_plural = '商品图片'
def __str__(self):
return self.title
# 轮播图Carousel: imgPath图片路径 describes图片描述
class Carousel(models.Model):
imgPath = models.CharField("轮播图路径",max_length=200)
describes = models.CharField("图片描述",max_length=200,null=True)
class Meta:
db_table = 'carousel_t'
verbose_name_plural = "轮播图"
def __str__(self):
return self.describes
六、获取首页轮播图商品
class CarouselAPIVIew(APIView):
def get(self,request):
try:
car_data = Carousel.objects.all()
ser = CarouselSerializer(car_data,many=True)
return Response({
'code':200,
'msg':'获取轮播图成功!',
'carousel':ser.data
})
except Exception as e:
return Response({
'code': 200,
'msg': '获取轮播图失败',
})
created() {
// 获取轮播图数据
this.$axios
.get("/goods/carousel/")
.then(res => {
console.log("@@carousel res:",res)
/***
*
* return Response({
* "code":"",
* "msg":"",
* "carousel":[{
* ”imgPath“:”“,
* ”describes“:”“,
* },{...},{...},{...}])
*/
this.carousel = res.data.carousel;
})
.catch(err => {
return Promise.reject(err);
});
七、根据类型获取商品和热门商品
# 获取一类商品信息
class OneCategory(APIView):
# 获取一类商品信息
def get(self,request):
# 1.获取种类信息
cate_name = request.query_params.get('categoryName')
# 2.ORM操作,获取种类信息
try:
cate_data = Category.objects.get(cate_name=cate_name)
except Exception as e:
print(e)
return Response({
'code':204,
'msg':'此商品不存在'
})
# 3.根据类别 获取 商品信息
goods_data = cate_data.goods_set.all()
# 4.序列化商品信息
ser = GoodsSerializer(goods_data,many=True)
return Response({
'msg':'成功获取商品信息',
'code':200,
'result':ser.data
})
# 热门商品
class HotProduct(APIView):
def get(self,request):
# 获取种类信息,热门商品是一个列表
cate_list = request.query_params.getlist('categoryName[]')
# 根据类别名获取种类信息(orm数据)
cate_data_list = []
for i in cate_list:
cate_data = Category.objects.get(cate_name=i)
cate_data_list.append(cate_data)
# 根据类别 获取 商品信息
goods_date_list = []
for i in cate_data_list:
goods_date_list.append(i.goods_set.all())
# 将商品信息合并
from functools import reduce
goods_data_queryset = reduce((lambda x,y:x|y),goods_date_list)
# 序列化
ser = GoodsSerializer(goods_data_queryset,many=True)
return Response({
'msg':'获取热门商品成功',
'code':200,
'result':ser.data
})
getPromo(categoryName, val, api) {
// 有API传入时,例子
// categoryName:["电视机", "空调", "洗衣机"],
// val:"applianceList",
// api:"/goods/getHotProduct/"
// 判断是否有api传进来
api = api != undefined ? api : "/goods/oneCategory/all/";
// if (api == undefined){
// api = "/goods/oneCategory/all/"
// }else{
// api = api
// }
//
this.$axios
.get(api, {
params: {categoryName:categoryName},
})
.then(res => {
console.log("@@获取"+categoryName+"的响应", res)
//获取属性,并赋值,如'phoneList'
this[val] = res.data.result;
})
.catch(err => {
return Promise.reject(err);
});
}
}
八、点击商品获取商品信息
# 获取一个商品的信息
class oneGoodAPIView(APIView):
def get(self,request):
# 1.获取商品id
good_id = request.query_params.get('productID')
# 2.根据id查询数据
try:
good_data = Goods.objects.get(id=good_id)
except Exception as e:
return Response({'msg':'商品不存在','code':204})
# 3.序列化数据
ser = GoodsSerializer(good_data)
return Response(ser.data)
# 获取一个商品的轮播图
class OneImg(APIView):
def get(self,request):
good_id = request.query_params.get('productID')
try:
good_data = Goods.objects.get(id=good_id)
except Exception as e:
return Response({
'msg':'图片不存在',
'code':204
})
img_data = good_data.goodimg_set.all()
ser = GoodimgSerializer(img_data,many=True)
return Response(ser.data)
getDetails(val) {//val为商品id
this.$axios
.get("/goods/onegood/", {
params:{productID: val}
})
.then(res => {
console.log("@@一个商品:", res)
this.productDetails = res.data;
// 然后模板就可以解析数据了
})
.catch(err => {
return Promise.reject(err);
});
},
// 获取商品图片
getDetailsPicture(val) {//通过商品id获取其图片
this.$axios
.get("/goods/onegood/imgs/", {
params:{productID: val}
})
.then(res => {
console.log("@详情页轮播图:",res)
this.productPicture = res.data;
})
.catch(err => {
return Promise.reject(err);
});
},
九、浏览历史记录
# 添加历史记录
class History(APIView):
def post(self,request):
# 1.判断用户是否登录
try:
user = User.objects.get(id=request.user_info.get('id'))
except Exception as e:
print(e)
return Response({'msg': '用户不存在或未登录', 'code': 204})
# 2.获取商品id
good_id = request.data.get('productID')
# 3.判断商品是否存在
try:
good_data = Goods.objects.get(id=good_id)
except Exception as e:
print(e)
return Response({'msg':'商品不存在','code':204})
# 4.添加历史记录
history_key = "history_%s"%user.username
r = redis.Redis(host='localhost',port=6379,password='password',db=0)
r.lrem(history_key,0,good_id)
r.lpush(history_key,good_id)
r.ltrim(history_key,0,4)
r.close()
return Response({'msg':'历史记录添加成功','code':200})
// 加入历史记录
addHistory(productID){
// 页面挂载完成,请求后端加入历史记录
this.$axios.post('/goods/oneGood/history/', {
productID: productID,
},{
headers:{
token: localStorage.getItem('token')||'' // JWT token
}})
.then(res => {
console.log("加入历史记录的响应:", res)
})
.catch(err => {
return Promise.reject(err)
})
},
十、收藏商品
# 收藏模型类
class GoodsCollect(models.Model):
user = models.ForeignKey(to=User,on_delete=models.CASCADE,verbose_name='用户')
goods = models.ForeignKey(to=Goods,on_delete=models.CASCADE,verbose_name='商品')
class Meta:
db_table = 'goods_collect'
verbose_name_plural = '商品收藏'
def __str__(self):
return '%S:%S' % (self.user.username,self.goods.sku_name)
from .models import GoodsCollect
# 收藏
class Collection(APIView):
# 添加收藏
def post(self,request):
# 1.判断用户是否登录
try:
user = User.objects.get(id=request.user_info.get('id'))
except Exception as e:
print(e)
return Response({'msg': '用户不存在或未登录', 'code': 204})
# 2.判断收藏是否存在
good_id = request.data.get('productID')
collect_data = GoodsCollect.objects.filter(user=user,goods_id=good_id)
if collect_data.count()>0:
return Response({'msg': '收藏已存在', 'code': 204})
# 3.收藏不存在,添加收藏
try:
GoodsCollect.objects.create(
user=user,
goods_id=good_id
)
except Exception as e:
print(e)
return Response({'msg': '添加收藏失败', 'code': 204})
return Response({'msg': '添加收藏成功', 'code': 200})
# 查询收藏
def get(self,request):
# 1.判断用户是否登录
try:
user = User.objects.get(id=request.user_info.get('id'))
except Exception as e:
print(e)
return Response({'msg': '用户不存在或未登录', 'code': 204})
# 2.查询用户的收藏
collec_data = GoodsCollect.objects.filter(user=user)
if collec_data.count() == 0:
return Response({'msg':'没有任何收藏','code':204})
# 3.处理收藏的数据
collec_list = []
for i in collec_data:
collec_list.append({
"id": i.goods.id,
"sku_name": i.goods.sku_name,
"title": i.goods.title,
"price": i.goods.price,
"selling_price": i.goods.selling_price,
"img": i.goods.img,
})
# 4.返回结果
return Response({'code':200,'collectList':collec_list})
# 删除收藏
def delete(self,request):
# 1.判断用户是否登录
try:
user = User.objects.get(id=request.user_info.get('id'))
except Exception as e:
print(e)
return Response({'msg': '用户不存在或未登录', 'code': 204})
# 2.根据商品id删除收藏
good_id = request.data.get('productID')
try:
GoodsCollect.objects.get(user=user,goods_id=good_id).delete()
except Exception as e:
print(e)
return Response({'msg':'删除收藏失败','code':204})
return Response({'msg':'删除收藏成功','code':200})
addCollect() {
// 判断是否登录,没有登录则显示登录组件
if (!this.$store.getters.getUser) {
this.$store.dispatch("setShowLogin", true);
return;
}
this.$axios
// 修改接口为goods
.post("/goods/user/collection/", {
productID: this.productID
},{headers:{token:localStorage.getItem("token") || ""}})
.then(res => {
console.log("@@添加收藏的响应:", res)
if (res.data.code == 200) {
// 添加收藏成功
this.notifySucceed(res.data.msg);
} else {
// 添加收藏失败
this.notifyError(res.data.msg);
}
})
.catch(err => {
return Promise.reject(err);
});
}
}
};
十一、加入购物车
# 购物车
class UserCart(APIView):
def post(self,reqeust):
# 1.判断用户是否登录
try:
user = User.objects.get(id=reqeust.user_info.get('id'))
except Exception as e:
print(e)
return Response({'msg': '用户不存在或未登录', 'code': 204})
# 2.获取商品信息
good_id = reqeust.data.get('productID')
good_data = Goods.objects.get(id=good_id)
# 拼接购物车的键
cart_key = "cart_%s"%user.username
# 添加购物车的商品自动勾选上
cart_selected_key = "cart_selected_%s"%user.username
# 3.判断库存
if good_data.stock<=0:
return Response({'msg':'库存不足,无法购买','code':203})
# 4.判断购物车是否存在该商品
r = redis.Redis(host='localhost',port=6379,db=0,password='password')
# 获取商品在购物车中的数量
num = r.hget(cart_key,good_id)
if num: # 购物车已存在商品
num = int(num.decode()) + 1
if num > good_data.stock:
return Response({'code':202,'msg':'加购达到限购数量'})
r.hset(cart_key,good_id,str(num)) # 购物车数量+1
r.sadd(cart_selected_key,good_id) # 选中商品
return Response({'code': 201, 'msg': '该商品已存在购物车,数量+1'})
else: # 购物车不存在该商品
r.hset(cart_key,good_id,1) # 添加商品到购物车
r.sadd(cart_selected_key, good_id) # 选中商品
r.close()
return Response({
'msg':'加入购物车成功',
'code':200,
'shoppingCartData':{
'id':cart_key, # 购物车名字
'productID':good_id, # 商品id
'productName':good_data.sku_name, # 商品名
'productImg':good_data.img,
'price':good_data.price,
'num':1,
'maxNum':good_data.stock,
'check':True
}
})
def get(self,reqeust):
# 1.判断用户是否登录
try:
user = User.objects.get(id=reqeust.user_info.get('id'))
except Exception as e:
print(e)
return Response({'msg': '用户不存在或未登录', 'code': 204})
# 拼接redis数据库中的键
cart_key = "cart_%s" % user.username
# 添加购物车的商品自动勾选上
cart_selected_key = "cart_selected_%s" % user.username
# 2.获取数据
r = redis.Redis(host='localhost',port=6379,password='password',db=0)
cart_list = r.hgetall(cart_key) # 读取购物车中的数据
select_list = r.smembers(cart_selected_key) # 读取选中的商品
select_list_2 = [i.decode() for i in select_list] # 解码
result_data = []
# key 商品id value 商品数量
for key,value in cart_list.items():
good_id = key.decode()
good_data = Goods.objects.get(id=good_id)
result_data.append({
'id':cart_key,
'productId':good_data.id,
'productName':good_data.sku_name,
'productImg':good_data.img,
'price':good_data.price,
'num':value.decode(),
'maxNum':good_data.stock,
# 如果商品id在 select_list_2里,就是选中的
'check':good_id in select_list_2,
})
return Response({
'msg':'查询购物车成功',
'code':200,
'shoppingCartData':result_data,
})
this.$axios
// 接口cart要改成goods
.post("/goods/user/cart/", {
productID: this.productID
}, {headers:{token:localStorage.getItem("token")||""}})
.then(res => {
console.log("@@添加购物车res:", res)
//
// 处理购物车的响应
switch (res.data.code) {
case 200:
// 新加入购物车成功
this.unshiftShoppingCart(res.data.shoppingCartData);
this.notifySucceed(res.data.msg);
break;
case 201:
// 该商品已经在购物车,数量+1
this.addShoppingCartNum(this.productID);
this.notifySucceed(res.data.msg);
break;
case 202:
// 商品数量达到限购数量(即库存量)
this.dis = true; //购物车按钮不可点击
this.notifyError(res.data.msg);
break;
case 203:
default:
this.notifyError(res.data.msg);
}
})
.catch(err => {
return Promise.reject(err);
});
},
十二、购物车中全选与数量加减
def put(self,request):
try:
user_info = request.user_info
user = User.objects.get(id=user_info.get('id'))
except Exception as e:
print(e)
return Response({'msg':'用户不存在或未登录!','code':404})
# 2.获取商品id和商品数量
good_id =request.data.get('productID')
num = request.data.get('num')
cart_key = 'cart_%s'%user.username
r = redis.Redis(host='localhost',port=6379,db=0,password='password')
r.hset(cart_key,good_id,num)
r.close()
return Response({'code':200,'msg':'数量修改成功'})
class GoodsSelect(APIView):
def put(self,request):
try:
user_info = request.user_info
user = User.objects.get(id=user_info.get('id'))
except Exception as e:
print(e)
return Response({'msg':'用户不存在或未登录!','code':204})
# 2.获取商品id和商品数量
good_id =request.data.get('productID')
select_flag = request.data.get('val')
cart_selected_key = 'cart_selected_%s' %user.username
# 3.修改redis数据库中的数据
r = redis.Redis(host='localhost', port=6379, db=0,password='password')
if select_flag:
r.sadd(cart_selected_key,good_id)
r.close()
return Response({'code': 200, 'msg': '%s修改成功' % good_id})
else:
r.srem(cart_selected_key,good_id)
r.close()
return Response({'code': 200, 'msg': '%s取消修改成功' % good_id})
def post(self, request):
# 1.判断用户是否登录
try:
user_info = request.user_info
user = User.objects.get(id=user_info.get("id"))
except Exception as e:
print(e)
return Response({
"code": 204,
"msg": '用户不存在或未登录'
})
# 2.获取全选的状态
all_flag = request.data.get("val")
cart_key = "cart_%s" % user.username
cart_selected_key = "cart_selected_key_%s" % user.username
# 3.修改选中状态
r = redis.Redis(host="localhost", port=6379,db=0,password='password')
if all_flag: # 全选
# 获取购物车中的商品id
good_id_list = r.hkeys(cart_key)
# 添加选中的商品
for i in good_id_list:
r.sadd(cart_selected_key, i.decode())
r.close()
return Response({
"code": 200,
"msg": '全选成功'
})
else: # 取消全选
# 删掉全选中的商品
r.delete(cart_selected_key)
r.close()
return Response({
"code": 200,
"msg": '取消全选成功'
})
this.$axios
// cart改成goods
.put("/goods/user/cart/", {
productID: productID,
num: currentValue,//更新过后的值
}, {headers: {'token': localStorage.getItem("token") || ""}})
.then(res => {
console.log("@@更新购物车的后端响应:", res)
switch (res.data.code) {
case 200:
// 200代表更新成功
// 更新vuex状态
this.updateShoppingCart({
key: key,
prop: "num",
val: currentValue
});
// 提示更新成功信息
this.notifySucceed(res.data.msg);
break;
default:
// 提示更新失败信息
this.notifyError(res.data.msg);
}
})
.catch(err => {
return Promise.reject(err);
});
},
// 单选
checkChange(val, key, cartID) {
console.log("单选的勾选状态:", val, key, cartID)
const productID = this.getShoppingCart[key].productID
// carts 改goods
this.$axios.put("/goods/user/selection/", {
productID,
val,
}, {headers: {token: localStorage.getItem("token") || ""}})
.then(res => {
if (res.data.code == 200) {
// 更新前端vuex中购物车商品勾选状态
this.updateShoppingCart({key: key, prop: "check", val: val});
this.notifySucceed(res.data.msg)
} else {
this.notifyError(res.data.msg)
}
})
.catch(err => {
return Promise.reject(err)
})
},
十三、实现获取用户信息、修改,添加,删除,地址
class UserCenter(APIView):
# 用户信息更新
def put(self,request):
# 1.判断用户是否登录
try:
user_info = request.user_info
user = User.objects.get(id=user_info.get('id'))
except Exception as e:
return Response({'code': 204, 'msg': '用户不存在或未登录!'})
# 2.获取前端提交的数据
phone = request.data.get('phone')
addrs_list = request.data.get('addrs')
# 3.修改用户的手机号
if not re.findall(r'^1[3-9]\d{9}$',phone):
return Response({'code':204,'msg':'手机号不正确'})
user.mobile = phone
user.save()
# 4.修改地址 循环 一个一个去改
for i in addrs_list:
Addr.objects.filter(id=i.get('id')).update(
receiver =i.get('receiver'),
receive_mobile = i.get('receive_mobile'),
receive_addr = i.get('receive_addr'),
is_default = i.get("is_default")
)
return Response({'msg':'修改信息成功','code':200})
# 获取用户信息
def get(self,request):
# 1.判断用户是否登录
try:
user_info = request.user_info
user = User.objects.get(id=user_info.get('id'))
except Exception as e:
return Response({'code':204,'msg':'用户不存在或未登录!'})
# 2.返回前端需要的数据
# addrs_list = []
# 查询用户的地址信息
addrs_data = user.addr_set.all()
ser = Addrser(addrs_data,many=True)
# for i in addrs_data:
# addrs_list.append({
# 'id':i.id,
# 'receiver':i.receiver,
# 'receive_mobile':i.receive_mobile,
# 'receive_addr':i.receive_addr,
# 'is_default':i.is_default
# })
return Response({
'code':200,
'msg':'获取用户信息成功',
'userInfo':{
'username':user.username,
'phone':user.mobile,
'addrs':ser.data
}
})
# 添加用户收货地址
class UserAddr(APIView):
def post(self,request):
# 1.判断用户是否登录
try:
user_info = request.user_info
user = User.objects.get(id=user_info.get('id'))
except Exception as e:
return Response({'code':204,'msg':'用户不存在或未登录!'})
# 2.获取前端提交的数据
receiver = request.data.get('receiver')
receive_mobile = request.data.get('receive_mobile')
receive_addr = request.data.get('receive_addr')
is_default = request.data.get('is_default')
# 3.判断数据是否齐全,手机号是否符合要求
if not all([receive_addr,receive_mobile,receiver]):
return Response({'msg':'信息不全','code':200})
if not re.findall(r'^1[3-9]\d{9}$',receive_mobile):
return Response({'msg':'手机不正确','code':204})
# 4.默认收货地址处理:只能有一个
if is_default:
# 查看该用户是否有默认地址
default_addr = Addr.objects.filter(user=user,is_default=True)
default_addr.update(is_default=False)
# 5.添加新地址
new_addr = Addr.objects.create(
receiver=receiver,
receive_mobile=receive_mobile,
receive_addr=receive_addr,
is_default=is_default,
user=user
)
ser = Addrser(new_addr)
return Response({'msg':'地址添加成功','code':200,'addr':ser.data})
# 删除地址
def delete(self,request):
# 1.判断用户是否登录
try:
user_info = request.user_info
user = User.objects.get(id=user_info.get('id'))
except Exception as e:
return Response({'code':204,'msg':'用户不存在或未登录!'})
addr_id = request.data.get('addr_id')
Addr.objects.filter(id=addr_id).delete()
return Response({'msg':'删除成功','code':200})
activated() {
// 未登录时,弹出登录组件
if (!this.$store.getters.getUser.userName) {
this.$store.dispatch("setShowLogin", true);
}
// 已登录,发送ajax请求,获取用户信息
this.$axios
.get("/users/user/", {
headers: {token: localStorage.getItem('token') || ""}
})
.then((res) => {
console.log("@@获取用户的信息:", res);
if (res.data.code == 200) {
this.userInfo = res.data.userInfo;
} else {
this.notifyError(res.data.msg);
}
})
.catch((err) => {
return Promise.reject(err);
});
},
methods: {
// 修改个人信息
updateUserInfo() {
console.log("修改个人信息...");
this.$axios.put("/users/user/", {
phone: this.userInfo.phone,
addrs: this.userInfo.addrs,
}, {
headers: {
token: localStorage.getItem("token") || ""
}
}).then(res => {
if (res.data.code == 200) {
this.notifySucceed(res.data.msg)
} else {
this.notifyError(res.data.msg)
}
})
},
// 添加地址
addAddr() {
console.log("增加地址...");
this.$axios
.post("/users/user/addr/", {
receiver: this.receiver,
receive_mobile: this.receive_mobile,
receive_addr: this.receive_addr, //字符串地址
is_default: this.is_default, //是否默认地址}
}, {
headers: {
token: localStorage.getItem("token") || ""
}
})
.then((res) => {
console.log("添加地址的响应:", res);
if (res.data.code == 200) {
this.userInfo.addrs.push(res.data.addr);
this.receiver = ""
this.receive_mobile = ""
this.receive_addr = ""
this.notifySucceed(res.data.msg);
} else {
this.notifyError(res.data.msg);
}
})
.catch((err) => {
return Promise.reject(err);
});
deleteAddr(e, addr_id) {
// 删除该地址
this.$axios.delete("/users/user/addr/", {
data: {addr_id: addr_id},
headers: { // 补上header
token: localStorage.getItem("token") || ""
},
}).then(res => {
if (res.data.code == 200) {
// 删除User组件中的对应地址
for (let i = 0; i < this.userInfo.addrs.length; i++) {
let temp = this.userInfo.addrs[i]
if (temp.id == addr_id) {
this.userInfo.addrs.splice(i, 1)
}
}
this.notifySucceed(res.data.msg)
} else {
// this.notifyError
this.notifyError(res.data.msg) // 补上
}
})
},
十四、修改密码
# 修改密码
class UpadatePass(APIView):
def put(self,request):
# 1.判断用户是否登录
try:
user_info = request.user_info
user = User.objects.get(id=user_info.get('id'))
except Exception as e:
return Response({'code':204,'msg':'用户不存在或未登录!'})
# 2.获取前端提交的数据
originPw = request.data.get('originPw')
newPw = request.data.get('newPw')
confirmNewPw = request.data.get('confirmNewPw')
# 3.判断原始密码是否正确
if not user.check_password(originPw):
return Response({'msg':'密码错误','code':204})
# 4.判断新密码和原密码是否一样
if originPw == newPw:
return Response({'msg': '密码没有修改', 'code': 204})
# 5.新密码两次密码不一致
if newPw != confirmNewPw:
return Response({'msg': '两次密码不一致', 'code': 204})
# 6.保存新密码
user.set_password(newPw)
user.save()
return Response({'msg': '修改密码成功', 'code': 200})
// 更改个人密码
updatePassword() {
console.log("修改个人密码...");
this.$store.dispatch("setUpdatePw", true);
},
// 点击修改密码触发
updatePassword() {
// 通过element自定义表单校验规则,校验用户输入的用户信息
this.$refs["ruleForm"].validate((valid) => {
//如果通过校验开始请求后端
if (valid) {
// 发送ajax
// this.$axios
console.log("开始发送请求,修改密码...")
axios
.put("/users/user/password/", {
originPw: this.LoginUser.originPw,
newPw: this.LoginUser.newPw,
confirmNewPw: this.LoginUser.confirmNewPw,
// withCredentials: true,
}, { // 补上header
headers: {
token: localStorage.getItem("token") || ""
},
})
.then((res) => {
console.log("@@res", res);
// 200代表登录成功,其他的均为失败
if (res.data.code == 200) {
// res.data为后端响应的json
// 隐藏修改密码组件
this.isUpdatePw = false;
// 重新登录
// this.setUser("");
// 弹出通知框提示登录成功信息
this.notifySucceed(res.data.msg);
} else {
//响应不是200
// 清空输入框的校验状态
this.$refs["ruleForm"].resetFields();
// 弹出通知框提示登录失败信息
this.notifyError(res.data.msg);
}
})
.catch((err) => {
console.log(err);
return Promise.reject(err);
});
} else {
//未通过用户校验
return false;
}
});
},