Django入门项目实战

一、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;
        }
      });
    },

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值