zoukankan      html  css  js  c++  java
  • 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 = []  
    

      

  • 相关阅读:
    tail命令和head命令查询文件指定行数
    php unserialize(): Error at offset 470 of 660 bytes
    屏蔽搜索引擎收录robots.txt文件下载
    php-apc为magento加速
    magento导入csv文件到数据库中乱码
    magento 上传csv表格中实例化对象例子
    magento上新产品,前台不显示不显示属性,后台却有属性问题
    php裁剪图片
    概念:静态static相关知识
    概念 : 重定向概念
  • 原文地址:https://www.cnblogs.com/LearningOnline/p/9478025.html
Copyright © 2011-2022 走看看