redis介绍及在购物车项目中的应用,用户认证
1.redis
2.购物车的构建
api结构:
models.py(创建完后自行添加数据)
- from django.db import models
- from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
- from django.contrib.contenttypes.models import ContentType
- # Create your models here.
- class Course(models.Model):
- """专题课/学位课模块表"""
- name = models.CharField(max_length=128, unique=True)
- course_img = models.CharField(max_length=255)
- course_type_choices = ((0, '付费'), (1, 'VIP专享'), (2, '学位课程'))
- course_type = models.SmallIntegerField(choices=course_type_choices)
- brief = models.TextField(verbose_name="课程概述", max_length=2048)
- # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除
- price_policy = GenericRelation("PricePolicy")
- class PricePolicy(models.Model):
- """价格与有课程效期表"""
- content_type = models.ForeignKey(ContentType) # 关联course
- object_id = models.PositiveIntegerField()
- content_object = GenericForeignKey('content_type', 'object_id')
- # course = models.ForeignKey("Course")
- valid_period_choices = ((1, '1天'), (3, '3天'),
- (7, '1周'), (14, '2周'),
- (30, '1个月'),
- (60, '2个月'),
- (90, '3个月'),
- (180, '6个月'), (210, '12个月'),
- (540, '18个月'), (720, '24个月'),
- )
- valid_period = models.SmallIntegerField(choices=valid_period_choices)
- price = models.FloatField()
- class Meta:
- unique_together = ("content_type", 'object_id', "valid_period")
- verbose_name_plural = "15. 价格策略"
- def __str__(self):
- return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)
- class Account(models.Model):
- username = models.CharField("用户名", max_length=64, unique=True)
- email = models.EmailField(
- verbose_name='邮箱',
- max_length=255,
- unique=True,
- blank=True,
- null=True
- )
- password = models.CharField('密码', max_length=128)
- class Meta:
- verbose_name_plural = "22. 账户信息"
- class UserToken(models.Model):
- user = models.OneToOneField(to='Account')
- token = models.CharField(max_length=36)
- class Meta:
- verbose_name_plural = "34. token表"
admin.py(用于在在admin中添加数据)
- from django.contrib import admin
- from api import models
- # Register your models here.
- admin.site.register(models.UserToken)
- admin.site.register(models.Course)
- admin.site.register(models.Account)
- admin.site.register(models.PricePolicy)
urls.py
- from django.conf.urls import url
- from api.views import shoppingcar,auth
- urlpatterns = [
- url(r'auth/$', auth.AuthView.as_view({'post': 'login'})),
- url(r'shoppingcar/$', shoppingcar.ShoppingCarView.as_view({'post': 'create', 'get': 'list',
- 'delete': 'destory', 'put': 'update'})),
- ]
app01下的urls.py
- from django.conf.urls import url,include
- from django.contrib import admin
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^api/(?P<version>\w+)/', include('api.urls')),
- ]
utils/response.py
- class BaseResponse(object):
- def __init__(self):
- self.code = 1000
- self.data = None
- self.error = None
- @property
- def dict(self):
- return self.__dict__
utils/auth.py(重写用户认证组件)
- from rest_framework.authentication import BaseAuthentication
- from rest_framework.exceptions import AuthenticationFailed
- from api import models
- class AccountAuthentication(BaseAuthentication):
- def authenticate(self, request):
- """
- 源码:
- Authenticate the request and return a two-tuple of (user, token).
- """
- # 从前端获取用户携带的token
- token = request.query_params.get('token')
- token_obj = models.UserToken.objects.filter(token=token).first()
- if not token_obj:
- raise AuthenticationFailed({'code':1000,'error':'认证失败'})
- # 认证通过
- return (token_obj.user, token_obj)
views/auth.py(登录认证)
- import uuid
- from rest_framework.views import APIView
- from rest_framework.viewsets import ViewSetMixin
- from rest_framework.response import Response
- from api import models
- from api.utils.response import BaseResponse
- class AuthView(ViewSetMixin,APIView):
- def login(self,request,*args,**kwargs):
- """api_usertoken
- 用户登录认证
- """
- response = BaseResponse()
- try:
- user = request.data.get('username')
- pwd = request.data.get('password')
- obj = models.Account.objects.filter(username=user,password=pwd).first()
- if not obj:
- response.code = 1000
- response.error = '用户名或密码错误'
- else:
- uid = str(uuid.uuid4())
- # UserToken和Account是一对一的关系,登陆成功生成uid并加入表格
- models.UserToken.objects.update_or_create(user=obj,defaults={'token':uid})
- response.code = 99999
- response.data = uid
- except Exception as e:
- response.code = 10005
- response.error = '操作异常'
- return Response(response.dict)
views/shoppingcar.py
- import json
- import redis
- from django.conf import settings
- from rest_framework.views import APIView
- from rest_framework.viewsets import ViewSetMixin
- from rest_framework.response import Response
- from api.utils.auth import AccountAuthentication
- from api.utils import response
- from api import models
- # 注意这里的ip地址
- CONN = redis.Redis(host="118.24.140.138",port=6379)
- class ShoppingCarView(ViewSetMixin, APIView):
- # 加入用户认证
- authentication_classes = [AccountAuthentication,]
- def list(self,request,*args,**kwargs):
- """
- 从redis中查看购物车信息
- """
- ret = response.BaseResponse()
- try:
- shopping_car_list = []
- # 这里的request.user来自认证组件的的返回值
- print(request.user)
- pattern = settings.LUFFY_SHOPPING_CAR % (request.user.id, '*',)
- user_key_list = CONN.keys(pattern)
- for key in user_key_list:
- temp = {
- "id":CONN.hget(key,"id").decode("utf-8"),
- "name":CONN.hget(key,"name").decode("utf-8"),
- "img":CONN.hget(key,"img").decode("utf-8"),
- }
- shopping_car_list.append(temp)
- ret.data = shopping_car_list
- except Exception as e:
- ret.code = 1000
- ret.error = "获取数据失败"
- return Response(ret.dict)
- def create(self, request, *args, **kwargs):
- """
- 加入购物车
- """
- # 需要先接收用户选中的课程id以及价格策略id
- course_id = request.data.get('courseid')
- policy_id = request.data.get('policyid')
- course = models.Course.objects.first(id=course_id)
- ret = response.BaseResponse()
- # 判断数据是否合法,防止非正常点击,比如利用其他软件0元购买某些商品
- try:
- # 判断课程是否存在
- if not course:
- ret.code = 1000
- ret.error = "课程不存在"
- return Response(ret.dict)
- # 判断价格策略的合法性,也是避免蓄意修改
- # 获取价格策略的所有信息
- price_policy_queryset = course.price_policy.all()
- price_policy_dict = {}
- for item in price_policy_queryset:
- temp = {
- 'id':item.id,
- 'price':item.price,
- 'valid_period': item.valid_period,
- 'valid_period_display': item.get_valid_period_display()
- }
- price_policy_dict[item.id] = temp
- # 校验id是是否在字典中
- if policy_id not in price_policy_dict:
- ret.code = 1000
- ret.error = "不要乱动"
- return Response(ret.dict)
- # 设置购物车物品数
- pattern = settings.LUFFY_SHOPPING_CAR % (request.user.id, '*',)
- keys = CONN.keys(pattern)
- if keys and len(keys) >=100:
- ret.code = 1000
- ret.error = "物品栏已满"
- return Response(ret.dict)
- except Exception as e:
- # 进行添加操作
- key = settings.LUFFY_SHOPPING_CAR % (request.user.id, course_id,)
- CONN.hset(key,'id',course_id)
- CONN.hset(key, 'name', course.name)
- CONN.hset(key, 'img', course.course_img)
- # 设置保存时长,24h
- CONN.expire(key,60*60*24)
- ret.code= 500
- ret.data = "保存成功"
- return Response(ret.dict)
- def update(self,request,*args,**kwargs):
- """
- 修改操作,这里我们只能修改我们的价格策略
- """
- ret = response.BaseResponse()
- try:
- # 获取用户通过操作相关字段传来的id
- course_id = request.data.get('courseid')
- policy_id = str(request.data.get('policyid'))
- key = settings.LUFFY_SHOPPING_CAR % (request.user.id, course_id,)
- if not CONN.exists(key):
- ret.code = 10000
- ret.error = '课程不存在'
- return Response(ret.dict)
- # 取我们存的price_policy_dict数据
- price_policy_dict = json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))
- # 判断价格策略是否存在
- if policy_id not in price_policy_dict:
- ret.code = 1000
- ret.error = '价格策略不存在'
- return Response(ret.dict)
- # 修改价格策略
- CONN.hset(key, 'default_price_id', policy_id)
- set.data = '修改成功'
- except Exception as e:
- ret.code = 1000
- ret.error = "修改失败"
- return Response(ret.dict)
- def destory(self,request,*args,**kwargs):
- """
- 删除选中的某个课程
- """
- ret = response.BaseResponse()
- try:
- course_id = request.data.get('courseid')
- # 获取它的key值
- key = settings.LUFFY_SHOPPING_CAR % (request.user.id, course_id,)
- CONN.delete(key)
- ret.data = "删除成功"
- except Exception as e:
- ret.code = 1000
- ret.error = "删除失败"
- return Response(ret.dict)
setting相关配制:
- INSTALLED_APPS = [
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'app01.apps.App01Config',
- 'api.apps.ApiConfig',
- 'rest_framework'
- ]
- REST_FRAMEWORK = {
- # 版本相关信息
- 'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
- 'VERSION_PARAM':'version',
- 'DEFAULT_VERSION':'v1',
- 'ALLOWED_VERSIONS':['v1','v2'],
- # 分页相关信息,数字代表一页几条数据
- # 'PAGE_SIZE':2
- }
- LUFFY_SHOPPING_CAR = "shopping_car_%s-%s"
测试(成功登录,获取它的token)
发送一个错误请求,这里直接被认证组件拦截了,并没有到达视图
在通过携带token发送一个get请求:
3.全局配置
如果100个类,有98个视图要认证。可以加到全局rest_framework里面
- 'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.LuffyAuthentication',]
对于某些不用认证的类,可以直接定义认证类为空列表即可
- authentication_classes = []
redis介绍及在购物车项目中的应用,用户认证的更多相关文章
- MVC项目中如何判断用户是在用什么设备进行访问
使用UAParser在C#MVC项目中如何判断用户是在用什么设备进行访问(手机,平板还是普通的电脑) 现在我们开发的很多web应用都要支持手机等移动设备.为了让手机用户能有更加好的用户体验,我们经常为 ...
- ssm项目中遇到微信用户名称带有表情,插入失败问题
ssm项目中遇到微信用户名称带有表情,插入失败问题 问题 Mysql的utf8编码最多3个字节,而Emoji表情或者某些特殊字符是4个字节. 因此会导致带有表情的昵称插入数据库时出错. 解决方法 一. ...
- Redis的安装以及在项目中使用Redis的一些总结和体会
第一部分:为什么我的项目中要使用Redis 我知道有些地方没说到位,希望大神们提出来,我会吸取教训,大家共同进步! 注册时邮件激活的部分使用Redis 发送邮件时使用Redis的消息队列,减轻网站压力 ...
- 缓存框架有使用过哪些?memcache和redis有什么区别?项目中,怎么去选择?
缓存有:ehcache,memcache和redis等 区别: 1. Redis和Memcache都是将数据存放在内存中,都是内存数据库.不过memcache还可用于缓存其他东西,例如图片.视频等等. ...
- 【redis】5.spring boot项目中,直接在spring data jpa的Repository层使用redis +redis注解@Cacheable直接在Repository层使用,报错问题处理Null key returned for cache operation
spring boot整合redis:http://www.cnblogs.com/sxdcgaq8080/p/8028970.html 首先,明确一下问题的场景 之前在spring boot整合re ...
- 使用UAParser在C#MVC项目中如何判断用户是在用什么设备进行访问(手机,平板还是普通的电脑)
现在我们开发的很多web应用都要支持手机等移动设备.为了让手机用户能有更加好的用户体验,我们经常为手机设备专门准备一套前端的页面.这样当用户使用普通电脑来访问的时候,我们的应用就向用户展示普通电脑的页 ...
- 在web项目中使用shiro(认证、授权)
一.在web项目中实现认证 第一步,在web项目中导入shiro依赖的包 第二步,在web.xml中声明shiro拦截权限的过滤器 <filter> <filter-name> ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(11)-切换用户
在某些应用场合中,我们可能需要用到切换用户的功能,从而以另一用户的身份进行相关操作.这一点类似于在Linux系统中,用su命令切换到另一用户进行相关操作. 既然实际应用中有这种场合,那么我们 ...
- C#中Fun简单介绍及运用到项目中与缓存(本地缓存,Redis)结合使用
1.简单介绍Fun C#中Fun和Action有点类似,都是一个委托方法,不同的是Func是有返回值的,而Action没有. (T)此委托封装的方法的参数类型. 备注:详情了解Fun到(https: ...
随机推荐
- jQuery中的DOM操作——《锋利的JQuery》
jQuery封装了大量DOM操作的API,极大提高了操作DOM节点的效率. 1.查找节点 通过我们上一节介绍了JQuery选择器,可以非常轻松地查找节点元素.不过,这时得到的是jQuery对象,只能使 ...
- django 将表数据通过API展示到页面上(转)
需求: 我在learn这个app下创建了两张表,其中一个表为user,我希望通过API,在页面是展示这些数据,当用户访问指定的url时,将表中所有对象展示到页面上. 先看learn/models.py ...
- 深入理解JavaScript系列(18):面向对象编程之ECMAScript实现(推荐)
介绍 本章是关于ECMAScript面向对象实现的第2篇,第1篇我们讨论的是概论和CEMAScript的比较,如果你还没有读第1篇,在进行本章之前,我强烈建议你先读一下第1篇,因为本篇实在太长了(35 ...
- jQuery autocomplete 应用
1. 引入css和js <link rel="stylesheet" href="{{ url_for('static', filename='jquery.aut ...
- Razor语句(VIew)小知识
1.可以写后台语句 例如:
- Spring课程 Spring入门篇 4-6 Spring bean装配之基于java的容器注解说明--@ImportResource和@Value java与properties文件交互
1 解析 1.1 这两个注解应用在什么地方 1.2 应用方式 1.3 xml方式实现取值 2 代码演练 2.1 @ImportResource和@Value代码演练 1 解析 1.1 这两个注解应用在 ...
- IO流之序列化流与反序列化流
序列化流与反序列化流 用于从流中读取对象的 操作流 ObjectInputStream 称为 反序列化流 用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流 l ...
- 原生js简单实现拖拽效果
实现弹窗拖拽效果的原理是:按下鼠标并移动——拖拽移动物体,抬起鼠标——停止移动.主要触发三个事件:onmousedown.onmousemove以及onmouseup: 首先搭建结构:一个宽350px ...
- C#使用Process类杀死进程,执行命令等
c#之process类相关整理 一.根据进程名获取进程的用户名? 需要添加对 System.Management.dll 的引用 using System.Diagnostics; using Sys ...
- iBrand 开源电商小程序 (Laravel API+ webpack + gulp + 原生小程序)
iBrand 社交电商产品正式进入开源过程中了,我们制定了详细的开源计划,目前已经发布了 V1 的版本,后续的版本也在陆续整理完善中. 各个版本功能明细如下图: 3 个版本计划在今年春节前全部完成,可 ...