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: ...
随机推荐
- SpringBoot | 第三十三章:Spring web Servcies集成和使用
前言 最近有个单位内网系统需要对接统一门户,进行单点登录和待办事项对接功能.一般上政府系统都会要求做统一登录功能,这个没啥问题,反正业务系统都是做单点登录的,改下shiro相关类就好了.看了接入方案, ...
- jqgrid 上移下移单元格
在表格中常常需要调整表格中数据的显示顺序,我用的是jqgrid,实现原理就是将表中的行数保存到数据库中,取数据时按行进行排序 1.上移,下移按钮 <a href="javascript ...
- java poi reader常用API汇总
注意:(1)判断行的最大数量建议使用sheet.getLastRowNum();(2)判断每行最大列数建议使用row.getLastCellNum(); [JAVA]特别注意,POI中getLastR ...
- 浅谈前端与SEO
转载地址: https://blog.csdn.net/lzm18064126848/article/details/53385274?tdsourcetag=s_pctim_aiomsg SEO(S ...
- 1.net平台
.net/dotnet:一般指的是.Net Framework框架,是一种平台,一种技术. .net Framewoek框架是.net平台不可缺少的一部分,它提供了一个稳定的运行环境来保证.net ...
- <转>MapReduce工作原理图文详解
转自 http://weixiaolu.iteye.com/blog/1474172前言: 前段时间我们云计算团队一起学习了hadoop相关的知识,大家都积极地做了.学了很多东西,收获颇丰.可是开学 ...
- Hibernate=====HQL实用技术
Hibernate支持三种查询语言:HQL查询.Criteria查询和原生SQL查询 HQL(hibernate Query Language,hibernate查询语言)是一种面向对象查询语言,其中 ...
- Spring课程 Spring入门篇 4-9 Spring bean装配之对jsr支持的说明
1 解析 1.1 疑问:2.2去掉@resource注解,为什么不能赋值?不是有set方法了吗? 1.2 @resource注解版本支持 1.3 没有显式指定@resource的那么,默认名称从何获得 ...
- Csharp: TreeView 初始化设置默认选择节点
/// <summary> /// 设置查找的节点为选定节点 /// 涂聚文 /// 2013-07-15 /// </summary> /// <param name= ...
- jQuery动态添加删除CSS样式
jQuery框架提供了两个CSS样式操作方法,一个是追加样式addClass,一个是移除样式removeClass,下面通过一个小例子讲解用法. jQuery动态追加移除CSS样式 <!DOCT ...