Django--dailyfresh--用户注册和登陆(1)

django-admin startproject dailyfresh
cd dailyfresh
# 新建 apps包 用于存放项目模块
cd apps
python manage.py startapp user
python manage.py startapp goods
python manage.py startapp cart
python manage.py startapp order

在这里插入图片描述
传统的 应用注册

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'apps.user',
    'apps.cart',
    'apps.order',
    'apps.goods',
)

修改默认的绝对路径
settings.py

import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0,os.path.join(BASE_DIR,'apps'))
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user',
    'cart',
    'order',
    'goods',
)

富文本编辑器

pip install django-tinymce==2.6.0
pip install Pillow
dailyfresh/settings.py
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import sys

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0,os.path.join(BASE_DIR,'apps'))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '9emu2f$d9wbp2hw)88=(p!iwco#@ni=3)4ewj3n=(^_)%(u*gv'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tinymce',      #富文本编辑器
    'user',         #用户模块
    'order',        #订单模块
    'cart',          #购物车模块
    'goods',         #商品模块
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

ROOT_URLCONF = 'dailyfresh.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'dailyfresh.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'dailyfresh',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST':'127.0.0.1',
        'PORT': 3306,
    }
}

#Django认证系统使用的模型类
AUTH_USER_MODEL = 'user.User'

# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static')]

# 富文本编辑器配置
TINYMCE_DEFAULT_CONFIG = {
    'theme': 'advanced',
    'width': 600,
    'height': 400,
}
dailyfresh/urls.py
from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^tinymce/',include('tinymce.urls')),                      #富文本编辑器
    url(r'^user/',include('user.urls',namespace='user')),           #用户模块
    url(r'^cart/',include('cart.urls',namespace='cart')),           #购物车模块
    url(r'order/',include('order.urls',namespace='order')),           #订单模块
    url(r'^',include('goods.urls',namespace='goods')),              #商品模块
]
apps/goods/urls.py
from django.conf.urls import url
from goods import views
urlpatterns = [
    url(r'^$',views.index,name='index')
]
apps/goods/views.py
from django.shortcuts import render
# Create your views here.
#http://127.0.0.1:8000
def index(request):
    '''首页'''
    return render(request,'index.html')
apps/user/urls.py
from django.conf.urls import url
from user import views
urlpatterns = [
    url(r'^register$',views.register,name='register'),  #注册
    url(r'^register_handle$',views.register_handle,name='register_handle'), #注册处理
]
apps/user/views.py
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse  #使用反向解析
from user.models import User
import re

# Create your views here.
# /user/register
def register(request):
    '''显示注册页面'''
        return render(request,'register.html')
        
def register_handle(request):
    #'''进行注册处理'''
    # 接收数据
    username = request.POST.get('user_name')
    password = request.POST.get('pwd')
    email = request.POST.get('email')
    allow = request.POST.get('allow')
    # 进行数据校验
    # all方法,对其中参数判断,都为真,all函数返回真
    if not all([username, password, email]):
        # 数据不完整
        return render(request, 'register.html', {'errmsg': '数据不完整'})

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

    # 是否同意协议,同意协议传过来的参数是 on
    if allow != 'on':
        return render(request, 'register.html', {'errmsg': '请同意协议'})

    # 校验用户名是否重复
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        # 用户不存在
        user = None

    if user:
        # 用户已存在
        return render(request, 'register.html', {'errmsg': '用户名已存在'})

    # 进行业务处理

    # 数据存储
    user = User.objects.create_user(username, email, password)
    user.is_active = 0
    user.save()

    # 返回应答, 跳转到首页
    return redirect(reverse('goods:index'))

在这里插入图片描述
在这里插入图片描述

注册页面和注册处理使用同一个URL

apps/urls/views.py
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse  #使用反向解析
from user.models import User
import re

# Create your views here.
# /user/register
def register(request):
    '''显示注册页面'''
    # 判断请求方式处理请求页面
    if request.method == 'GET':
        # 显示注册页面
        return render(request,'register.html')
    else:
        # 进行注册处理
        # 接收数据
        username = request.POST.get('user_name')
        password = request.POST.get('pwd')
        email = request.POST.get('email')
        allow = request.POST.get('allow')
        # 进行数据校验
        # all方法,对其中参数判断,都为真,all函数返回真
        if not all([username, password, email]):
            # 数据不完整
            return render(request, 'register.html', {'errmsg': '数据不完整'})

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

        # 是否同意协议,同意协议传过来的参数是 on
        if allow != 'on':
            return render(request, 'register.html', {'errmsg': '请同意协议'})

        # 校验用户名是否重复
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            # 用户不存在
            user = None

        if user:
            # 用户已存在
            return render(request, 'register.html', {'errmsg': '用户名已存在'})

        # 进行业务处理

        # 数据存储
        user = User.objects.create_user(username, email, password)
        user.is_active = 0
        user.save()

        # 返回应答, 跳转到首页
        return redirect(reverse('goods:index'))

更改注册页面HTML
在这里插入图片描述

基于类试图实现 注册页面

apps/user/views.py
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse  #使用反向解析
from user.models import User
from django.views.generic import View  # 类试图
import re
class RegisterView(View):
    '''注册类'''
    def get(self,request):
        '''显示注册页面'''
        return render(request,'register.html')

    def post(self,request):
        '''进行注册处理'''
        # 接收数据
        username = request.POST.get('user_name')
        password = request.POST.get('pwd')
        email = request.POST.get('email')
        allow = request.POST.get('allow')
        # 进行数据校验
        # all方法,对其中参数判断,都为真,all函数返回真
        if not all([username, password, email]):
            # 数据不完整
            return render(request, 'register.html', {'errmsg': '数据不完整'})

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

        # 是否同意协议,同意协议传过来的参数是 on
        if allow != 'on':
            return render(request, 'register.html', {'errmsg': '请同意协议'})

        # 校验用户名是否重复
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            # 用户不存在
            user = None

        if user:
            # 用户已存在
            return render(request, 'register.html', {'errmsg': '用户名已存在'})

        # 进行业务处理

        # 数据存储
        user = User.objects.create_user(username, email, password)
        user.is_active = 0
        user.save()

        # 返回应答, 跳转到首页
        return redirect(reverse('goods:index'))
apps/user/urls.py
from django.conf.urls import url
from user.views import RegisterView
urlpatterns = [
    url(r'^register$',RegisterView.as_view(),name='register'), #注册
]

激活用户token

itsdangerous 内部默认使用基于HMAC和SHA1来签名,基于 Django签名模块

pip install itsdangerous

使用简介:

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
serializer = Serializer('secretkey',3600)
info = {'confirm':1}
res = serializer.dumps(info) #对 info 进行加密
res  # 返回加密信息

b'eyJhbGciOiJIUzUxMiIsImlhdCI6MTU2NTYwOTE4NCwiZXhwIjoxNTY1NjEyNzg0fQ.eyJjb25maXJtIjoxfQ._nMyozjltsFrk7cNYD2eT7rjLDl4bwE0Ur15Z-k5RM_cZyqkv0WYji9gvbJqaNUIAI_Rvld_VjG4Fu6dIC8Dxw'

serializer.loads(res)  # 解密,加密是一个字典,解密也是一个字典

第一个参数是秘钥,第二个参数是过期小时(以秒为单位)

apps/user/views.py
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse  #使用反向解析
from user.models import User
from django.http import HttpResponse
from django.views.generic import View  # 类试图
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer  # 签名模块
from itsdangerous import SignatureExpired  # 签名过期异常
from django.core.mail import send_mail       # 发送邮件
from django.conf import settings  # 导入 dailyfresh/settings.py 的配置项
import re
class RegisterView(View):
    '''注册类'''
    def get(self,request):
        '''显示注册页面'''
        return render(request,'register.html')

    def post(self,request):
        '''进行注册处理'''
        # 接收数据
        username = request.POST.get('user_name')
        password = request.POST.get('pwd')
        email = request.POST.get('email')
        allow = request.POST.get('allow')
        # 进行数据校验
        # all方法,对其中参数判断,都为真,all函数返回真
        if not all([username, password, email]):
            # 数据不完整
            return render(request, 'register.html', {'errmsg': '数据不完整'})

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

        # 是否同意协议,同意协议传过来的参数是 on
        if allow != 'on':
            return render(request, 'register.html', {'errmsg': '请同意协议'})

        # 校验用户名是否重复
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            # 用户不存在
            user = None

        if user:
            # 用户已存在
            return render(request, 'register.html', {'errmsg': '用户名已存在'})

        # 进行业务处理

        # 数据存储
        user = User.objects.create_user(username, email, password)
        user.is_active = 0
        user.save()

        # 发送激活邮件,包含激活链接:
        # 激活链接中需要包含用户的身份信息 http://127.0.0.1:8000 /user/active/ 数据库ID
        # 不能明文发送,需要加密

        # 加密用户用户信息,生成激活token
        # 秘钥可以使用  dailyfresh/settings.py 中 SECRET_KEY
        serializer = Serializer(settings.SECRET_KEY,3600)     # 3600=1h 过期
        info = {'confirm':user.id}
        token = serializer.dumps(info)  # bytes 类型
        token = token.decode('utf8')    # 转换为 utf8 字符串

        # 发送邮件
        # 邮件标题 通过 subject 指定, message 邮件正文, sender 指定发件人, receiver 收件人列表, html_message 将消息渲染称HTML
        subject = '天天生鲜欢迎信息'
        message = ''
        sender = settings.EMAIL_FROM
        html_message = '<h1> %s, 欢迎您成为天天生鲜注册会员</h1> 请点击下面链接激活您的账户 <br/> <a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s </a>' %(username,token,token)
        receiver = [email]
        send_mail(subject,message,sender,receiver,html_message=html_message)
        # 返回应答, 跳转到首页
        return redirect(reverse('goods:index'))

# 激活视图
class ActiveView(View):
    '''用户激活'''
    def get(self,request,token):
        '''进行用户激活'''
        # 解密,获取要激活的用户信息
        serializer = Serializer(settings.SECRET_KEY, 3600)  # 3600=1h 过期
        try:
            info = serializer.loads(token)
            # 获取激活用户的id
            user_id = info['confirm']
            # 根据id 获取获取用户信息
            user = User.objects.get(id=user_id)
            user.is_active = 1
            user.save()

            # 激活成功,调整到登录界面
            return redirect(reverse('user:login'))
        except SignatureExpired as e:
            # 激活链接已过期
            return HttpResponse('激活链接已过期')

# /user/login
# 登录视图
class loginView(View):
    '''登录'''
    def get(self,request):
        '''显示登录页面'''
        return render(request,'login.html')
apps/user/urls.py
from django.conf.urls import url
from user.views import RegisterView,ActiveView,loginView
urlpatterns = [
    url(r'^register$',RegisterView.as_view(),name='register'), #注册
    url(r'^active/(?P<token>.*)',ActiveView.as_view(),name='active'),  # 用户激活
    url(r'^login/$',loginView.as_view(),name='login'),    #登录
]
dailyfresh/settings.py 中设置邮箱
# 发送邮件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# smpt服务地址
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
# 发送邮件的邮箱
EMAIL_HOST_USER = 'smart@163.com'
# 在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'root'
# 收件人看到的发件人
EMAIL_FROM = '天天生鲜<smart@163.com>'

celery 异步发送邮件

pip install celery==4.1.1
pip install redis

在项目文件夹下,新建 ·celery_tasks python package 文件包 作为发送者任务方

celery_tasks/tasks.py
# 使用celery
from celery import Celery                   #导入 Celery 类
from django.conf import settings            # 导入dailyfresh/settings.py 中配置信息
from django.core.mail  import send_mail     #导入 发送邮件函数
import time

#创建一个Celery 对象
app = Celery('celery_tasks.tasks',broker='redis://127.0.0.1:6379/8')
#第一个参数是路径, broker 定义队列

#定义任务函数
@app.task
def send_register_active_email(to_email,username,token):    # 发送邮件地址,用户,token信息
    '''发送激活邮件'''
    # 发送邮件
    # 邮件标题 通过 subject 指定, message 邮件正文, sender 指定发件人, receiver 收件人列表, html_message 将消息渲染称HTML
    subject = '天天生鲜欢迎信息'
    message = ''
    sender = settings.EMAIL_FROM
    html_message = '<h1> %s, 欢迎您成为天天生鲜注册会员</h1> 请点击下面链接激活您的账户 <br/> <a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s </a>' % (username, token, token)
    receiver = [to_email]
    send_mail(subject, message, sender, receiver, html_message=html_message)
    time.sleep(30)
apps/user/views.py
from celery_tasks.tasks import send_register_active_email  #导入 celery 中定义的任务函数
class RegisterView(View):
		...
        # 发送邮件
        # 使用 celery 发送异步邮件, 使用delay方法
        send_register_active_email.delay(email,username,token)
        # 返回应答, 跳转到首页
        return redirect(reverse('goods:index'))

处理者
在使用Redis 另一台机器上(或同一台机器上)同样拷贝 项目文件,进入项目文件目录

celery -A celery_tasks.tasks worker -l info
# Django 配置初始化,以便celery的监听工作者 可以使用 Django中的一些信息
# 在任务处理者一段,添加如下代码
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")   #源码在 dailyfresh/wsgi.py 中
django.setup()

异常问题处理

Task handler raised error: ValueError('not enough values to unpack (expected 3, got 0)',)
网上的一些博客说是windows 不支持 celery4+, linux上支持
解决方法参考链接

pip install eventlet

支持异步处理命令 添加一个参数

celery -A celery_tasks.tasks worker -l info -P eventlet

在这里插入图片描述

登录校验

apps/user/views.py
from django.contrib.auth import authenticate    # 用户登录认证模块
# 认证一组指定的用户名和密码,它接收关键字参数形式的凭证,使用默认配置对象是username和password,如果密码能够匹配指定的用户名,返回一个User对象,否则返回None
from django.contrib.auth import login
# 有一个认证的用户,使用login函数将其放入session会话中,它接收一个HTTPRequest对象和一个User对象,使用Django的session框架来讲用户的ID保存在session中
class loginView(View):
    '''登录'''
    def get(self,request):
        '''显示登录页面'''
        return render(request,'login.html')

    def post(self,request):
        '''登录校验'''
        # 接收数据
        username = request.POST.get('username')
        password = request.POST.get('pwd')

        # 校验数据
            # 是否都 传递成功
        if not all([username,password]):
            return render(request,'login.html',{'errmsg':'数据不完整'})
        # 业务处理
            # 登录校验
        user = authenticate(username=username,password=password)
        if user is not None:
            # 正确,验证用户是否激活
            if user.is_active:
                # 密码正确 ,记录用户登录状态
                login(request,user)

                # 页面跳转,跳转首页
                return redirect(reverse('goods:index'))

            else:
                return render(request,'login.html',{'errmsg':'用户未激活,请激活您的账号'})
        else:
            # 用户密码不正确
            return render(request,'login.html',{'errmsg':'用户名或密码不正确'})

配置Redis作为Django缓存和Session存储后端

pip install django-redis==4.8.0

参考指南

apps/dailyfresh/settings.py
# Django 配置Redis缓存
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/9",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}
# Redis 作为session backend 使用配置:配置session存储
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

在这里插入图片描述
Redis 客户端输出

127.0.0.1:6379[9]> keys *
1) ":1:django.contrib.sessions.cacheksskn9cekdz5u6q2qqwtrudyk6y79twf"

实现 记住用户名

apps/user/views.py
class loginView(View):
    '''登录'''
    def get(self,request):
        '''显示登录页面'''
        # 判断是否记住了用户名
        if 'username' in request.COOKIES:
            username = request.COOKIES.get('username')
            checked = 'checked'
        else:
            username = ''
            checked = ''
        #使用 ,输出传入模板
        return render(request,'login.html',{'username':username,'checked':checked})

    def post(self,request):
        '''登录校验'''
        # 接收数据
        username = request.POST.get('username')
        password = request.POST.get('pwd')

        # 校验数据
            # 是否都 传递成功
        if not all([username,password]):
            return render(request,'login.html',{'errmsg':'数据不完整'})
        # 业务处理
            # 登录校验
        user = authenticate(username=username,password=password)
        if user is not None:
            # 正确,验证用户是否激活
            if user.is_active:
                # 密码正确 ,记录用户登录状态
                login(request,user)

                response = redirect(reverse('goods:index')) # 是一个HttpResponseRedirect 对象类

                # 判断是否需要记住用户名
                remember = request.POST.get('remember')
                if remember =='on':
                    # 记住用户名
                    response.set_cookie('username',username,max_age=7*24*3600)  #第二参数是过期时间,单位秒
                else:
                    # 不记住,session删掉
                    response.delete_cookie('username')

                # 页面跳转,跳转首页
                return response

            else:
                return render(request,'login.html',{'errmsg':'用户未激活,请激活您的账号'})
        else:
            # 用户密码不正确
            return render(request,'login.html',{'errmsg':'用户名或密码不正确'})
templates/login.html 输入标签添加vlue
<input type="text" name="username" class="name_input" value="{{ username }}" placeholder="请输入用户名">
<input type="checkbox" name=""> {{ checked }}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值