前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Django实战-生鲜电商-登录|注册|激活

Django实战-生鲜电商-登录|注册|激活

作者头像
小团子
发布2019-07-18 16:04:12
1.4K0
发布2019-07-18 16:04:12
举报
文章被收录于专栏:数据云团数据云团

完成了模型层,需要映射到数据库中,创建相应的表。在项目的 settings.py 文件中配置数据库,Django 有数据读写分离的配置方式。

创建新的项目,Django 会默认使用 sqlite 数据库

代码语言:javascript
复制
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

再执行 python manage.py makemigrations 命令之前,需要在 settings.py 文件中重载新建的 User 模型,然后再执行 python manage.py migrate 命令,将迁移文件,映射到数据库中,创建相应的表。

代码语言:javascript
复制
# django认证系统使用的用户模型
AUTH_USER_MODEL = "users.User"

配置读写分离路由器

代码语言:javascript
复制
DATABASE_ROUTERS = ["utils.db_router.MasterSlaveDBRouter"

在项目路径下创建 utils 文件夹,新建 db_router.py 文件,再创建 MasterSlaveDBRouter 类。

代码语言:javascript
复制
class MasterSlaveDBRouter(object):
    """读写分离路由"""
    def db_for_read(self, model, **hints):
        """读"""
        return "slave"

    def db_for_write(self, model, **hints):
        """写"""
        return "default"

    def allow_relation(self, obj1, obj2, **hints):
        """允许关联查询"""
        return True

一、发送邮件

使用 python 的 celery (分布式任务队列) 模块,实现用户注册邮箱激活功能。

需要在项目路径下,新建 celery_tasks 的 python 包,再创建 tasks.py 文件

代码语言:javascript
复制
from celery import Celery
import os

os.environ["DJANGO_SETTINGS_MODULE"] = "ihome.settings"

# 放到celery服务器上时将注释打开
# import django
# django.setup()

from django.core.mail import send_mail
from django.conf import settings
from goods.models import GoodsCategory, IndexGoodsBanner, IndexPromotionBanner
from goods.models import IndexCategoryGoodsBanner
from django.template import loader

# celery -A celery_tasks.tasks worker -l info


# 创建celery应用对象
app = Celery("celery_tasks.tasks", broker="redis://192.168.108.57/4")


@app.task
def send_active_email(to_email, user_name, token):
    """发送激活邮件"""
    subject = "生鲜用户激活"  # 标题
    body = ""  # 文本邮件体
    sender = settings.EMAIL_FROM  # 发件人
    receiver = [to_email]  # 接收人
    html_body = '<h1>尊敬的用户 %s, 感谢您注册生鲜!</h1>' \
                '<br/><p>请点击此链接激活您的帐号<a href="http://127.0.0.1:8000/users/active/%s">' \
                'http://127.0.0.1:8000/users/active/%s</a></p>' % (user_name, token, token)
    send_mail(subject, body, sender, receiver, html_message=html_body)

在 settings.py 文件中的配置

代码语言:javascript
复制
# Email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_FROM = ''

二、用户注册

代码语言:javascript
复制
class RegisterView(View):
    """用户注册"""
    def get(self, request):
        """处理get请求, 提供注册页面"""
        return render(request, "register.html")

    def post(self, request):
        """处理post请求,处理注册数据"""
        # 获取前端发送的数据/参数
        user_name = request.POST.get("user_name")
        password = request.POST.get("pwd")
        email = request.POST.get("email")
        allow = request.POST.get("allow")

        # 参数校验
        if not all([user_name, password, email]):
            # 如果参数不完整,从定向到注册页面
            return redirect(reverse("users:register"))

        if not re.match(r"^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$", email):
            # 如果email格式不正确
            return render(request, "register.html", {"errmsg": "邮箱格式不正确!"})

        if allow != "on":
            # 如果用户没有勾选协议
            return render(request, "register.html", {"errmsg": "请同意协议!"})

        # 进行业务逻辑处理
        # 将密码加密
        # 将用户数据保存到数据库中
        # user = User()
        # user.save()

        # 使用django的认证系统创建用户
        try:
            user = User.objects.create_user(user_name, email, password)
        except db.IntegrityError:
            # 如果抛出此异常,表示用户已经注册
            return render(request, "register.html", {"errmsg": "用户已注册!"})

        # 将用户的激活状态设置为假
        user.is_active = False
        user.save()

        # 生成激活token
        token = user.generate_active_token()

        # 使用celery发送邮件
        send_active_email.delay(email, user_name, token)

        # 返回给前端结果
        return redirect(reverse("goods:index"))

三、用户激活

代码语言:javascript
复制
class ActiveView(View):
    """激活"""
    def get(self, request, token):
        # 根据token 解析,获取用户的id
        # 创建转换工具(序列化器)
        s = Serializer(settings.SECRET_KEY, 3600)
        # 解析
        try:
            ret = s.loads(token)
        except SignatureExpired:
            # 如果出现异常,表示token过期,返回信息给用户
            return HttpResponse("激活链接已过期")

        # 更新用户在数据库中的激活状态
        user_id = ret.get("confirm")
        # 查询数据库
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            # 用户不存在
            return HttpResponse("用户不存在")

        user.is_active = True
        user.save()

        # 返回信息给用户
        return redirect(reverse("users:login"))

四、用户登录

代码语言:javascript
复制
class LoginView(View):
    """登录"""
    def get(self, request):
        """提供登录页面"""
        return render(request, "login.html")

    def post(self, request):
        """处理登录请求"""
        user_name = request.POST.get("username")
        password = request.POST.get("pwd")
        remembered = request.POST.get("remembered")

        if not all([user_name, password]):
            return redirect(reverse("users:login"))

        #
        # password = sha256(password)
        # User.objects.get(username=user_name, password=password)

        # 使用django的认证系统
        user = authenticate(username=user_name, password=password)
        if user is None:
            # 表示用户的认证失败
            return render(request, "login.html", {"errmsg": "用户名或密码错误"})

        # 表示用户认证成功
        # 判断用户的激活状态
        if user.is_active is False:
            # 表示用户未激活
            return render(request, "login.html", {"errmsg": "用户名尚未激活"})

        # 在session中保存用户的登录状态信息
        login(request, user)

        # 处理记住用户名的逻辑
        if remembered != "on":
            # 不需要记住用户状态
            # 使用set_expiry设置 session 有效期
            request.session.set_expiry(0)
        else:
            # 需要记住用户状态
            request.session.set_expiry(None)

        # 将cookie中的购物车数据与redis中的购物车数据合并
        # 从cookie中获取购物车数据
        cart_json = request.COOKIES.get("cart")
        if cart_json is not None:
            cart_cookie = json.loads(cart_json)
        else:
            cart_cookie = {}

        # 从redis中获取购物车数据
        redis_conn = get_redis_connection("default")
        cart_redis = redis_conn.hgetall("cart_%s" % user.id)

        # 进行合并
        # cart_redis.update(cart_cookie)
        for sku_id, count in cart_cookie.items():
            # 在redis中的键与值都是bytes类型, 在cookie中的sku_id是str类型
            sku_id = sku_id.encode()  # 将str类型的sku_id转为bytes类型
            if sku_id in cart_redis:  # {b'1': b'3'}
                # cookie中有的商品,在redis中也有,进行数量求和,再设置到redis对应的购物车中
                origin_count = cart_redis[sku_id]
                count += int(origin_count)

            cart_redis[sku_id] = count

        # 将合并的购物车数据保存到redis中
        if cart_redis:
            redis_conn.hmset("cart_%s" % user.id, cart_redis)

        # 清除cookie中的购物车数据
        # 登录成功,根据next参数跳转页面
        next = request.GET.get("next")
        if next is None:
            # 如果没有next参数,跳转到主页
            response = redirect(reverse("goods:index"))
        else:
            # 如果next存在,跳转到next路径
            response = redirect(next)

        response.delete_cookie("cart")
        return response
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据云团 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档