Django项目之Web端电商网站的实战开发(二)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/88790662
目录
一丶用户注册
1.显示用户注册页面
- step1 在static目录下将register.html文件拷贝到templates模板目录下
- step2 在df_user模块下的views视图中定义一个register函数,定义这个函数的路由正则匹配为/user/register,显示用户注册页面
# /user/register
def register(request):
"""显示注册页面"""
return render(request, "register.html")
- step3 在df_user模块下的urls地址中配置注册页面正则规则,以及调用视图函数中的register函数
urlpatterns = [
url(r"^register$", views.register, name="register") # 注册页
]
- step4 运行项目,在浏览器中输入http://127.0.0.1:8000/user/register后,将注册页面渲染到浏览器上
- step5 出现上面这种情况是,页面所需要的图片和css以及js文件路径错误404,因为此时的register.html文件放在了templates模板目录下,所以需要在register.html中动态获取路径,需导入静态资源,然后修改每个链接,因为之前在settings配置文件中配置了静态文件URL为/static/所以这里只需要写之后的路径即可
{% load staticfiles %}
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>天天生鲜-注册</title>
<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}">
- step6 刷新页面,成功显示出页面内容
2.定义注册页面表单数据视图函数
- step1 首先注册页面数据是以POST请求方式向服务器发送,那么在register.html文件中找到form表单标签,编写用户点击注册按钮后向服务器请求的url地址
<form method="post" action="/user/register_handle">
- step2 在django中发送POST请求表单数据,防止跨站攻击需在form标签下加上{% csrf_token %}
<form method="post" action="/user/register_handle">
{% csrf_token %}
- step3 在df_user/views视图函数中定义register_handle方法,用于处理注册页面数据
# /user/register/handle
def register_handle(request):
"""处理用户注册数据"""
pass
- step4 在在df_user/urls路由地址中定义register_handle视图函数正则匹配规则
url(r"^register_handle$", views.register_handle, name="register_handle") # 注册数据处理
3.视图函数register_handle代码逻辑实现
- step1 接收注册表单数据
username = request.POST.get("user_name")
password = request.POST.get("pwd")
email = request.POST.get("email")
allow = request.POST.get("allow")
- step2 判断用户传递过来的数据是否存在,不存在返回错误信息提示
if not all([username, password, email]):
return render(request, "register.html", {"error_msg":"数据不完整"})
- step3 判断用户填写的邮箱是否为正确邮箱
if not re.match(r"^[a-z0-9][\w.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$", email):
return render(request, "register.html", {"error_msg":"邮箱格式不正确"})
- step4 判断用户注册时是否勾选同意,同意后该字段POST请求参数为on
if allow != "on":
return render(request, "register.html", {"error_msg":"请勾选同意"})
- step5 进行用户注册,将数据保存在数据库用户名中, 因为在执行迁移文件时,在settings中配置了django认证系统指定的模型类为df_user.User 所以可以不使用传统方式向类中添加属性再保存到数据库,而是直接使用django认证系统封装好的create_user函数将数据直接保存到数据库
user = User.objects.create_user(username, email, password)
- step6 注册成功后,使用反向解析跳转到首页 reverse(根基urls中的主页的namespace:goods模块中的urls主页的name)
return redirect(reverse("goods:index"))
- step7 为了显示主页,将static目录下的index.html文件拷贝到templates目录下,并加载静态资源文件{% load staticfiles %}修改index.html中的静态文件路径,这个页面的地址比较多,体力活
- step8 在df_goods/views中定义index视图函数
# http://127.0.0.1:8000
def index(request):
"""显示首页"""
return render(request, "index.html")
- step9 紧接着在df_goods/urls进行正则路由配置
urlpatterns = [
url(r"^$", views.index, name="index"), # 首页
]
- step10 查看数据库中的用户信息表
- step11 运行项目,在浏览器中输入http://127.0.0.1:8000/user/register,进行注册页,填写注册信息,点击注册按钮
说明:前端注册页面使用js对密码长度和两次密码是否一致以及邮箱地址是否同意都进行了校验
- step12 当点击注册按钮时,此时在会跳转到form表单中的action地址(/user/register_handle),匹配df_user/urls中的正则然后调用df_user/views中的register_handle视图函数,处理完数据后最终重定向到主页(index.html)
- step13 查看数据库df_user表数据,因为使用了django认证系统也就通俗点说在df_user/models中的User类继承了AbstractUser类,所以django的认证系统已经将用户注册时填写的密码进行加密处理后存到数据库,这样我们就不用在视图函数中获取密码并加密然后再保存到数据库表中
- step14 django认证系统默认用户表字段is_active为1(激活),所以这里需要进行设置为0(未激活)
user.is_active = 0
user.save()
- step15 再此回到注册页面,进行另一个用户注册,验证上一步is_active默认是否为未激活状态
- step16 使用已经注册过的账号进行注册,查看django认证系统错误提示
- step17 提示信息为用户名已存在,但这样的显示页面不是我们想要的
- step18 在进行用户注册之前,需要判断用户注册的用户名是否存在
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
"""如果出现该异常说明用户名不存在,则让user对象为空"""
user = None
# 如果user对象存在,则表示用户名已存在,返回错误提示信息
if user:
return render(request, "register.html", {"error_msg":"用户名已存在"})
4.测试数据不合法的情况下,提示错误信息
- step1 在register.html中form标签下添加error_msg变量
<span style="color: red">{{ error_msg }}</span>
- step2 注册已存在的用户名cdtaogang,查看错误提示
- step3 填写错误邮箱地址,然后点击注册
- step4 不填写任何数据直接进行注册
5.注册优化处理,让显示注册页面和注册数据处理为同一个url地址(/user/register) ,因为显示注册页面为get请求,而注册数据处理为post请求,可以根据请求方式不同来使用同一个url地址
- step1 在register.html中将form表单action地址修改为/user/register与显示页面地址一致
<form method="post" action="/user/register">
- step2 在df_user/views中的register视图函数中进行请求方式判断
# Create your views here.
# /user/register
def register(request):
"""注册"""
# 当请求方式为get时表示请求注册页面,反之为处理用户注册数据
if request.method == "GET":
"""显示注册页面"""
return render(request, "register.html")
else:
"""处理用户注册数据"""
- step3 注册一个新用户
- step4 查看数据库用户表
6.使用类视图来区分用户请求
- step1 在df_user/views视图中定义RegisterView视图类,在这个类中定义注册所需的get方法以及post方法,这个方法名必须等同于请求方式名
from django.views.generic import View
# /user/register
class RegisterView(View):
"""注册"""
def get(self, request):
"""显示注册页面"""
return render(request, "register.html")
def post(self, request):
"""处理用户注册数据"""
- step2 在df_user/urls中需导入RegisterView类,并调用这个类所属父类View中的as_view方法来根据请求方式调用对应的方法完成代码逻辑
urlpatterns = [
url(r"^register$", RegisterView.as_view(), name="register"), # 注册
]
- step3 刷新注册页,进行新用户注册
7. 生成用户激活邮件中的token,当在不错的网站进行用户注册成功后,会想用户注册填写的邮箱地址发送账户激活的邮件,在这个邮件内容中会有一个激活的链接地址,并且会提示用户请在2小时内进行激活,2小时后失效;定义激活链接为http://127.0.0.1:8000/user/active/用户id,如果在链接地址明文显示用户的id值的话,就会出现某些懂技术的用户,修改链接地址中的用户id,就很有可能去激活其他用户,所以需要将链接地址中的用户id值进行加密并设置密钥的有效期
- step1 安装itsdangerous模块,使用改模块生成我们所需的token
pip install itsdangerous
- step2 导致该模块中的TimedJSONWebSignatureSerializer类
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
- step3 加密用户id,生成激活的token
serializer = Serializer(settings.SECRET_KEY, 3600) # 有效期1小时
info = {"confirm":user.id}
token = serializer.dumps(info)
8.使用django内置函数发送邮件(这个QQ邮箱为博主小小小小号)
- step1 这里有QQ邮箱为例,进入QQ邮箱设置,开启POP3/SMTP服务
- step2 使用提示的密保手机向指定的号码发送指定内容来完成验证
- step3 发送成功后,显示出授权码,记住此授权码后,点击保存设置
- step4 在settings配置文件中进行发送邮件配置
# 发送邮件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'
EMAIL_PORT = 25
#发送邮件的邮箱
EMAIL_HOST_USER = '2384005622@qq.com'
#在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = '授权码'
#收件人看到的发件人
EMAIL_FROM = '天天生鲜<2384005622@qq.com>'
- step5 在df_user/view视图中导入django内置函数中的send_mail方法
from django.core.mail import send_mail
- step6 在RegisterView类中调用send_mail方法发送邮件
subject = "天天生鲜欢迎你" # 邮件标题
message = "how are you" # 邮件正文
sender = settings.EMAIL_FROM # 发件人
receiver = [email] # 收件人
send_mail(subject, message, sender, receiver)
- step7 注册一个新用户
- step8 登录注册时的邮箱,查看收件箱
- step9 向邮箱发送账户激活链接地址,htmp_message参数为渲染html标签后再进行内容发送
subject = "天天生鲜欢迎你" # 邮件标题
message = '' # 邮件正文
sender = settings.EMAIL_FROM # 发件人
receiver = [email] # 收件人
html_message = """
<h1>%s 恭喜您成为天天生鲜注册会员</h1><br/><h3>请您在1小时内点击以下链接进行账户激活</h3><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>
""" % (username, token, token)
send_mail(subject, message, sender, receiver, html_message=html_message)
- step10 注册一个新用户
- step11 查看邮件
- step12 点击邮件中的链接地址
9.用户注册激活
- step1 在df_user/views视图中定义ActiveView类,在这个类中定义get方法,用于处理用户激活
# /user/active/......
class ActiveView(View):
"""账户激活"""
def get(self, request, token):
"""进行用户激活"""
pass
- step2 获取加密的serializer对象
serializer = Serializer(settings.SECRET_KEY, 3600)
- step3 解密token,获取要激活的用户信息,首先需要导入itsdangerous包中的SignatureExpired类来处理超时异常,所以接下里的代码需要写到try里面
try:
info = serializer.loads(token)
# 获取用户id
user_id = info['confirm']
# 根据用户id 获取该用户对象
user = User.objects.get(id=user_id)
# 设置该用户对象中的is_active字段的值为1
user.is_active = 1
user.save()
# 使用反向解析跳转到登录页
return redirect(reverse("user:login"))
except SignatureExpired as e:
# 出现异常表示链接失效
return HttpResponse("激活链接已过期")
- step4 创建LoginView类并在这个类中定义get方法用于显示登录页
# /user/login
class LoginView(View):
"""登录"""
def get(self, request):
"""显示登录页"""
return render(request, "login.html")
- step5 在df_user/urls中定义以上两个类视图对应的正则以及对应的方法调用,将static目录下的login.html文件拷贝到templates目录下
url(r"^active/(?P<token>.*)$", ActiveView.as_view(), name="active"), # 账户激活
url(r"^login$", LoginView.as_view(), name="login"), # 登录
- step6 注册一个新用户,查看数据库中is_active的值
- step7 查看邮箱邮件信息
- step8 在邮箱中点击链接地址进行激活操作,成功跳转到登录页
- step9 查看数据库,该用户is_active字段的是为1表示已激活
10.使用celery异步发送邮件
- step1 在项目目录下创建celery_tasks包,在该包下创建tasks.py文件
- step2 在tasks.py文件中创建Celery实例对象
app = Celery("celery_tasks.tasks", broker="redis://127.0.0.1:6379/4")
- step3 定义任务函数send_active_email,说明之所以睡眠5秒是为了体现celery异步的强大
@app.task
def send_active_email(to_email, username, token):
"""发送用户激活邮件"""
subject = "天天生鲜欢迎你" # 邮件标题
message = '' # 邮件正文
sender = settings.EMAIL_FROM # 发件人
receiver = [to_email] # 收件人
html_message = """
<h1>%s 恭喜您成为天天生鲜注册会员</h1><br/><h3>请您在1小时内点击以下链接进行账户激活</h3><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>
""" % (username, token, token)
send_mail(subject, message, sender, receiver, html_message=html_message)
# 为了体现出celery异步完成发送邮件,这里睡眠5秒
time.sleep(5)
- step4 另打开一个Terminal终端,执行celery -A celery_tasks.tasks worker -l info 运行任务处理者,需要在broker所在的服务器中执行,需要注意的是windows不支持celery4.0以上的版本
- step5 注册一个新用户,注册成功跳转到首页后,查看celery处理者运行日志,发现报错了,导致用户注册成功,但邮件并未发送成功原因是在tasks.py文件中导入了项目配置文件settings,而未在执行任务进行初始化,并且在windows环境中要成功使用celery,celery版本必须在4.0以下,任务队列(中间人)redis数据库版本必须在3.0以下,博主经验
- step6 在tasks.py文件中添加如下代码,作用于worker工作室初始化django配置,因为博主这里使用celery是将任务发布者和中间人(broker)以及任务处理者(worker)在一台主机上运行,所以将下面的初始化配置写在这里,该初始化配置是跟随worker走的
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
django.setup()
- step7 在新终端中执行celery -A celery_tasks.tasks worker -l info,然后进行新用户注册
- step8 查看celery运行日志,显示成功,时间为6秒,之所以这么长时间是因为在send_active_email函数中睡眠5秒,由此可见尽管睡眠五秒,但用户在注册的时候根本感觉不到,注册成功瞬间跳转到主页,说明使用celery进行异步发送邮件的重要性
- step9 查看用户表
- step10 查看redis数据库
二丶用户登录
1.显示登录页面
- step1 在用户注册时已经定义了LoginView类视图中的get方法,显示登录页,所以直接在login.html文件中定义form表单请求方式以及请求地址,注:action不写默认表示与登录地址一致,跟用户注册一样,使用同一地址显示并处理登录
<form method="post">
{% csrf_token %}
- step2 在浏览器中输入http://127.0.0.1:8000/user/login,显示出登录页
2.处理登录数据校验
- step1 在类视图LoginView中定义post函数
def post(self, request):
"""登录校验"""
pass
- step2 接收用户填写的数据
username = request.POST.get("username")
password = request.POST.get("pwd")
- step3 校验参数完整性
if not all([username, password]):
return render(request, "login.html", {"error_msg":"数据不完整"})
- step4 校验用户名密码,当用户名密码正确情况下保存登录状态到session中,使用django认证系统中的authenticate和login方法
user = authenticate(username=username, password=password) # 正确返回user对象,不正确返回None
if user is not None:
# 用户名密码正确
if user.is_active:
# 用户已激活
# 将用户登录成功后状态保存在session,使用django认证系统中的login方法
login(request, user)
# 重定向到主页
return redirect(reverse("goods:index"))
else:
# 用户未激活
return render(request, "login.html", {"error_msg":"账户未激活"})
else:
# 用户名或密码错误
return render(request, "login.html", {"error_msg":"用户名或密码错误"})
3.进行登录测试 ,查看网页走下方红色字样提示
- step1 登录已激活的账户
- step2 登录不存在的账号
- step3 登录未激活的账号,这里有一个bug那就是在进行未激活账号登录时一直提示用户名和密码错误,在post方法中通过打印username和password的值查看输入的用户名和密码没错与当初注册时填写的用户名密码对的上,查看django认证系统文档,方法时候啥的都没问题,但是在校验用户名密码时调用的authenticate方法一直返回的是None,这就很奇怪了,通过网上查资料发现需要在settings配置文件中添加如下配置,让django认证系统中的create_user方法再保存用户注册数据时,不关联用户表中的is_active字段,这样再进行登录验证时调用authenticate方法返回错误的None对象
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']
- step4 不填写数据直接登录
4.配置django缓存以及session数据存储后端到redis数据库,django默认将session数据存储到mysql数据库(settings配置的数据库)中的django_session表中
- step1 安装django-redis包
pip2 install django-redis
- step2 在settings中添加django缓存配置以及设置django-redis作为session存储后端
# django缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/5",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
# 使用django-redis 作为 session 储存后端
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
- step3 查看reids中5库中的键
- step4 进行用户登录,服务器返回响应的sessionid
- step5 查看redis数据库
5.用户勾选记住用户名
- step1 在保存用户登录状态代码中进行如下代码逻辑判断,当用户勾选记住用户名时,remember的值为on,并将用户名保存到cookie中
# 因为redirect方法返回的是HttpResponseRedirect对象,而这个对象是HttpResponse的子类,所以可以设置cookie
response = redirect(reverse("goods:index"))
# 判断用户是否记勾选记住用户名
remember = request.POST.get("remember")
if remember == "on":
# 表示勾选了,将用户名保存在cookie中
response.set_cookie("username", username, max_age=7*24*3600)
else:
# 删除cookie
response.delete_cookie("username")
# 重定向到主页
return response
- step2 在显示登录页面get函数中判断用户是否记住用户名,记住用户名则获取cookie中的username并且设置勾选框为checked勾选状态,并返回给前端模板中
# 判断是否勾选记住用户名
if 'username' in request.COOKIES:
username = request.COOKIES.get("username")
checked = "checked"
else:
username=''
checked = ''
return render(request, "login.html", {"username":username, "checked":checked})
- step3 在login.html中设置用户名username标签的value值,以及remember的值
<input type="text" name="username" class="name_input" value="{{ username }}" placeholder="请输入用户名" autocomplete="off">
<input type="checkbox" name="remember" {{ checked }}>
- step4 测试登录时记住用户名
- step5 勾选记住用户名后,查看网站cookie看到刚设置的名为username的cookie了
- step6 测试登录时不记住用户名
Django项目之Web端电商网站的实战开发(二)的更多相关文章
- Django项目之Web端电商网站的实战开发(一)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 目录 一丶项目介绍 二丶电商项目开发流程 三丶项目需求 四丶项目架构概览 五丶项目数据库设计 六丶项目框架搭建 一丶项目介绍 产品 ...
- Django项目之Web端电商网站的实战开发(三)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
- 项目二:企业级java电商网站开发(服务端)
声明:项目源于网络,支持正版教程,学习使用,仅记录在此 项目介绍 企业级java电商网站开发(服务端),模块划分:用户管理,商品管理,商品品类管理,订单管理,订单详情管理,购物车管理,收货地址管理,支 ...
- vue第十七单元(电商项目逻辑处理,电商划分)
第十七单元(电商项目逻辑处理,电商划分) #课程目标 1.什么是电商项目 2.什么是B2B,B2C,C2C模式,常见的电商项目 3.移动端电商项目常见的逻辑处理 4.[知识扩展]传统系统架构及分布式系 ...
- web前端Vue+Django rest framework 框架 生鲜电商项目实战视频教程 ☝☝☝
web前端Vue+Django rest framework 框架 生鲜电商项目实战视频教程 web前端Vue+Django rest framework 框架 生鲜电商项目实战视频教程 学习 ...
- web前端Vue+Django rest framework 框架 生鲜电商项目实战✍✍✍
web前端Vue+Django rest framework 框架 生鲜电商项目实战 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频 ...
- 项目实战2—实现基于LVS负载均衡集群的电商网站架构
负载均衡集群企业级应用实战-LVS 实现基于LVS负载均衡集群的电商网站架构 背景:随着业务的发展,网站的访问量越来越大,网站访问量已经从原来的1000QPS,变为3000QPS,网站已经不堪重负,响 ...
- 如何一步一步用DDD设计一个电商网站(二)—— 项目架构
阅读目录 前言 六边形架构 终于开始建项目了 DDD中的3个臭皮匠 CQRS(Command Query Responsibility Segregation) 结语 一.前言 上一篇我们讲了DDD的 ...
- 引爆潮流技术 Vue+Django REST framework打造生鲜电商项目
引爆潮流技术Vue+Django REST framework打造生鲜电商项目 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受, ...
随机推荐
- Scala具体解释---------Scala是什么?可伸展的语言!
Scala是什么 Scala语言的名称来自于"可伸展的语言". 之所以这样命名,是由于他被设计成随着使用者的需求而成长.你能够把Scala应用在非常大范围的编程任务上.从写个小脚本 ...
- [Android随笔]内存泄漏以及内存溢出
名词解释 内存泄漏:memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏危害能够忽略,但内存泄漏堆积后果非常严重,不管多少内存,迟早会被占光. 内存溢出:out of ...
- IDEA中的maven web 项目中如何设置自己的本地仓库
我们在创建maven项目的时候如何不使用系统指定的本地仓库,而使用自己设置的仓库呢,这里小女子就来进行讲解一下吧! 讲解一:你要想找到settings.xml你就要自己我去官网上去下载apache-m ...
- LSTM入门学习——结合《LSTM模型》文章看
摘自:https://zybuluo.com/hanbingtao/note/581764 写得非常好 见原文 长短时记忆网络的思路比较简单.原始RNN的隐藏层只有一个状态,即h,它对于短期的输入非常 ...
- ES6学习笔记(一)新的变量定义命令let和const
1.一些历史 ES6(ECMAScript 6.0)是 JavaScript 语言的新一代标准,于2015 年 6 月正式发布,距今已经4年了,它的目标,是使得 JavaScript 语言可以用来编写 ...
- BZOJ3569: DZY Loves Chinese II(线性基构造)
Description 神校XJ之学霸兮,Dzy皇考曰JC. 摄提贞于孟陬兮,惟庚寅Dzy以降. 纷Dzy既有此内美兮,又重之以修能. 遂降临于OI界,欲以神力而凌♂辱众生. 今Dzy有一魞歄图, ...
- chown---改变某个文件或目录的所有者和所属的组
chown命令改变某个文件或目录的所有者和所属的组,该命令可以向某个用户授权,使该用户变成指定文件的所有者或者改变文件所属的组.用户可以是用户或者是用户D,用户组可以是组名或组id.文件名可以使由空格 ...
- python第六次作业——随笔
第一就是教的和布置的作业难度不一样.python在课堂上学到的东西太基础.然而作业基本上在教义是不能直接找到公式照搬的(尤其是第五次作业文件处理要用到pandas和numpy),所以做作业只能自己去找 ...
- JAVA工程命名规范
Java推荐的包声明命名约定是反向域名. 例如 - com.abysm.myproject
- 【Henu ACM Round#15 B】A and B and Compilation Errors
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 开3个map, 存在map里面: 然后迭代第一个和第二个map; 分别与第二个和第三个map比较就可以了 [代码] #include ...