XX商城........................................................................ 1
1. 项目需求分析...................................................... 6
1.1. 概念............................................................... 6
1.1.1. 原因...................................................... 6
1.1.2. 方式...................................................... 6
1.1.3. 内容...................................................... 6
1.1.4. 结果...................................................... 6
1.2. 页面|业务逻辑............................................. 6
1.2.1. 注册........................................................ 6
1.2.2. 登陆........................................................ 6
1.2.3. 首页........................................................ 6
1.2.4. 商品搜索................................................ 6
1.2.5. 商品列表................................................ 6
1.2.6. 商品详情页............................................ 6
1.2.7. 个人信息................................................ 6
1.2.8. 购物车.................................................... 6
1.2.9. 订单页.................................................... 6
1.2.10. 收货地址............................................ 6
1.2.11. 订单的确认........................................ 6
1.2.12. 提交订单............................................ 7
1.2.13. 支付宝支付........................................ 7
1.2.14. 支付宝处理结果................................ 7
1.2.15. 商品评价............................................ 7
1.3. 划分模块 | 功能....................................... 7
1.3.1. 用户.................................................. 7
1.3.2. 验证.................................................... 7
1.3.3. 第三方登陆...................................... 7
1.3.4. 首页广告......................................... 7
1.3.5. 商品 ............................................... 7
1.3.6. 购物车...............................................7
1.3.7. 订单 ................................................. 7
1.3.8. 支付 ................................................... 7
1.3.9. MIS系统.............................................. 7
2. 架构设计.............................................................. 7
2.1. 开发模式.......................................................... 7
2.2. 后端框架......................................................... 8
2.2.1. 页面的整体刷新...................................... 8
2.3. 前端框架........................................................ 8
2.3.1. 页面的局部刷新...................................... 8
2.4. 部分静态化..................................................... 8
2.5. Nginx............................................................. 8
2.6. uwsgi............................................................ 8
3. 工程创建和配置.................................................. 8
3.1. 创建仓库....................................................... 8
3.1.1. 在gitee中创建项目............................. 8
3.1.2. 新建 .gitignore文件............................. 8
3.1.3. 新建分支................................................ 9
3.1.4. 克隆仓库................................................ 9
3.1.5. 在仓库里克隆公用分支........................ 9
3.1.6. 在仓库里新建本地分支........................ 9
3.1.7. [git回顾] 配置ssh公钥.................... 9
3.2. 创建项目..................................................... 10
3.2.1. 使用django虚拟环境........................ 10
3.2.2. pycharm ............................... 10
3.2.4. 设置配置信息.......................... 10
3.3. 配置............................................................. 10
3.3.1. 1、修改配置文件................................ 10
3.3.2. 2、jinja2............................................... 11
3.3.3. 3、MySQL数据库............................... 12
3.3.4. 4、Redis数据库 读写速度快.......... 14
3.3.5. 5、日志................................................ 15
3.3.6. 6、静态文件........................................ 17
4. 目录结构............................................................ 17
4.1. logs.............................................................. 17
4.2. manage.py................................................... 18
4.3. 工程同名文件............................................. 18
4.3.1. setting.................................................. 18
4.3.2. static..................................................... 18
4.3.3. templates............................................. 18
4.3.4. utils....................................................... 18
4.3.5. libs........................................................ 18
4.3.6. apps...................................................... 18
4.3.7. __init__.py........................................... 18
4.3.8. urls.py................................................... 18
4.3.9. wsgi.py................................................. 18
5. 模块功能实现.................................................... 18
5.1. 用户注册..................................................... 18
5.1.1. 展示用户注册页面.............................. 19
5.1.2. 用户模型类.......................................... 20
5.1.3. 业务实现.............................................. 21
5.2. 验证码......................................................... 25
5.2.1. 图形验证码.......................................... 25
5.2.2. 短信验证码.......................................... 27
5.2.3. 优化...................................................... 30
5.2.4. 异步方案.............................................. 31
5.3. 用户登陆..................................................... 33
5.3.1. 账号登陆.............................................. 33
5.3.2. QQ登陆............................................... 35
5.4. 用户中心..................................................... 37
5.4.1. 用户基本信息...................................... 37
5.4.2. 添加和验证邮箱.................................. 37
5.4.3. 收货地址.............................................. 40
5.4.4. 修改密码.............................................. 40
5.5. 商品............................................................. 40
5.5.1. 商品数据库表的设计.......................... 41
5.5.2. 准备商品数据...................................... 41
5.5.3. 首页广告.............................................. 41
5.5.4. 商品列表页.......................................... 41
5.5.5. 商品搜索.............................................. 41
5.5.6. 商品详情页.......................................... 41
5.5.7. 用户浏览记录...................................... 41
5.6. 购物车......................................................... 41
6. 性能优化............................................................ 41
7. 部署.................................................................... 41
git checkout -b dev origin/dev
origin/div:跟踪远程分支,修改会进行差异合并,否则:本地覆盖远程(git checkout -b dev origin/dev, git checkout -b dev)
参见: django-admin startproject XX_MALL
vi .gitconfig [震惊项!] (是在用户打开终端的默认路径下,而不是在工程里 修改用户名和邮箱为gitee注册使用的内容)
ssh-keygen -t rsa -C '邮箱地址' ---->一路回车加y---->cd .ssh/---->cat id_rsa.pub (note: 公钥:id_rsa_pub 私钥: id_rsa)
参见: 在仓库里新建本地分支
2、把原来的settings文件拉入包中,重命名dev(开发环境配置文件)
3、修改manage.py文件--指定配置(因为在manage.py文件执行)
在settings模板中添加jinja2---'BACKEND': 'django.template.backends.jinja2.Jinja2', # jinja2模板引擎
1、在工程总工程目录下创建一个template目录——存放模板文件
2、告诉jinja2在哪找模板文件 :TEMPLATE 'DIRS': [os.path.join(BASE_DIR, 'templates')],
3、notes: BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
templates--->右键--->make directory as unmake as template folder
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment
def jinja2_environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse,
})
return env
"""
确保可以使用Django模板引擎中的{% url('') %} {% static('') %}这类的语句
"""
确保可以使用Django模板引擎中的{% url('') %} {% static('') %}这类的语句
使模板生效,在TMPLATES中补充jinja2模板引擎环境:
'environment': 'meiduo_mall.utils.jinja2_env.jinja2_environment',
create database name charset=utf8
create user name identified by 'password'
删除用户;delete from mysql.user where user='' and host='';
查看用户:select host,user,password from mysql.user;
删除用户的数据库:drop database database_name;
grant all on databasename.* to 'username'@'%'
% : 任何ip--->名为modle_one的用户可以在任意一台电脑上访问数据库(代表不同ip 的的用户都能使用该数据库)
DATABASES = {}DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'model_one', # 数据库用户名
'PASSWORD': '123456', # 数据库用户密码
'NAME': 'XX_MALL' # 数据库名字
},
}
工程同名子目录__init__.py下: from pymysql import install_as_MySQLdb (导入) as_MySQLdb()
安全!MySQLroot 权限非常高(2、新建用户, 3、授权)
配置缓存(caches)default and session | 都是固定内容,仅:"LOCATION": "redis://127.0.0.1:6379/0", 可改。
指定session方案——用Redis保存在名叫session缓存中:SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "session"
CACHES = {
"default": { # 默认
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
"session": { # session
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "session"
default:
默认的Redis配置项,采用0号Redis库。
session:
状态保持的Redis配置项,采用1号Redis库。
SESSION_ENGINE
修改session存储机制使用Redis保存。
SESSION_CACHE_ALIAS:
使用名为"session"的Redis配置项存储session数据。
配置完成后:运行程序,测试结果。
添加: 'filename': os.path.join(os.path.dirname(BASE_DIR),--->决定了logs目录的位置
LOGGING = {
'version': 1,
'disable_existing_loggers': False, # 是否禁用已经存在的日志器
'formatters': { # 日志信息显示的格式
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
},
'simple': {
'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
},
},
'filters': { # 对日志进行过滤
'require_debug_true': { # django在debug模式下才输出日志
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': { # 日志处理方法
'console': { # 向终端中输出日志
'level': 'INFO',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file': { # 向文件中输出日志
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(os.path.dirname(BASE_DIR), 'logs/meiduo.log'), # 日志文件的位置
'maxBytes': 300 * 1024 * 1024,
'backupCount': 10,
'formatter': 'verbose'
},
},
'loggers': { # 日志器
'django': { # 定义了一个名为django的日志器
'handlers': ['console', 'file'], # 可以同时向终端与文件中输出日志
'propagate': True, # 是否继续传递日志信息
'level': 'INFO', # 日志器接收的最低日志级别
},
}
}
进入工程目录: vim .gitignore中添加*.log
3、在logs中新建一个.gitkeep的文件,因为这个文件不以.log结尾,可以被git 管理。从而避免了logs整个目录不被管理。——结果:每个人都有logS这个文件,但每个人都不一样
2、告诉django去哪找静态文件----->指定静态文件加载路径 :
static_url = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
note: BASE_DIR是计算出来的结果,所以静态文件路径并不固定。
session存在缓存中,缓存存在redis中(4、Redis数据库
读写速度快)
3、注册用户模块:'XX_MALL.apps.users.apps.UsersConfig'
基于manage.py 运行==基于mange.py导包(路径是从manage.py开始的)
sys.path: 列表--->指定虚拟环境路径==>python导包路径
python导包:1、当前路径 2、sys.path列表中依次找
sys.path.insert(0,os.path.join(BASE_DIR,'apps'))
BASE_DIR=自己的项目同名目录。 将meiduo_mall.apps添加到导包路径中。insert(0)列表的插入语句,把该路径放到列表第一位
子路由: url(r'^register/$',views.RegisterView.as_view()),
总路由中:url(r'^',include("users.urls"))
users.urls: 不会有提示,因为该路径并不完整,但是我们指定其上级目录为导包路径,不需要写全。
so: 上级apps-->右键---->makedirectory as resourceroot
视图中定义返回:render(request,Register.html)Register.html的试图函数
1、注册的本质:根据用户信息新建一个用户对象<=>像mysql数据库中insert into一条数据
位置:settings-->django.contrib.auth 包含认证框架的核心和默认的模型
1、from django.contrib.auth.models import AbstractUser
django提供的贡献功能 -认证-模型-AbstracUser
2、此时系统中有两个User,需指定执行哪个User。
AUTH_USER_MODEL = 'users.User' 应用名称.模型类
放在setting-->dev的最后
执行报错:ValueError: Dependency on app with no migrations: users
3、创建迁移文件:python manage.py makemigrations
4、执行迁移文件:python manage.py migrate
接收(五种方式)、验证、处理、响应(视图)
常用http协议:get :(查询)post:(加) put(改) delete(删)
class RegisterView(View):
1、提供注册界面 :def get(self, request): 返回注册界面
2 实现用户注册 :def post(self, request): 返回注册结果
2、总路由:url(r'^', include('users.urls', namespace='users')),
3、子路由: url(r'^register/$', views.RegisterView.as_view(), name='register'),
输出:原来使用双大括号(jinja2在浏览器向客户端发送请求后,只要遇到双大括号就执行,变量不存在就报错。但是vue.js在js执行之后才执行——请求过程:浏览器发送请求-->服务器返回html\csss\js'\....然后才执行js-->vue.js),现在使用双中括号。
username = request.POST.get('前端的标签name')
passsword =
判断信息是否完整:if not all([参1,参2,.....]) --->all方法会挨个遍历内部列表返回有值为空则执行
判断信息格式是否正确:if not re.math('^正则能表达式$',username)
判断用户名是否重复: from .modles import User if User.object.filter(username=username).count()>0:
校验成功-->创建用户:user = User.object.create_user( josn数据 )
create_user封装了用户密码加密方式,在创建用户对象时比create好使。
var url = this.host + '/usernames/' + this.username + '/count/';
axios.get(url, {
responseType: 'json'
})
补:ajax 是发送http请求获取后台服务器数据的技术
ajax的简写方式可以使用$.get和$.post方法来完成
如果是和vue+axios : 纯发送Ajax 用于发行Ajax请求的js库 。方便。轻量
接收、验证、处理P(得到count())、响应(返回count、状态码)
1、count = User.object.filter(username=username).count>0:
if User.objects.filter(mobile=mobile).count()>0:
请求一个视图---->生成4位字符串-->视图中画一个图片-->响应,指定数据类型为image/png
text/html---->mimetype类型(表示数据的格式)
运行captcha.py--输出--->元组(变量1,变量2,变量3)第二个变量为图片中的字符,第三个变量为图片二进制数据
class Captcha(object):....# 类
captcha = Captcha.instance() # 对象
if __name__ == '__main__':
print(captcha.generate_captcha()) # 调用对象generate_captcha()方法
text ,code,image = captcha.generate_captcha()
新建文件夹中添加:IMAGE_CODE_EXPIRES = 60 * 5
redis_cli = get_redis_connection('image_code') #缓存名
redis_cli.setex(uuid,constans.IMAGE_CODE_EXPIRES,code) # SETEX key seconds value
return http.HttpResponse(image,content_type='image/png'
url('^image_codes/(?P<uuid>[\w-]+)/$',views.ImageCodeView.as_view()),
定义get方法:def get(self,request,uuid):
因为:浏览器遇到img标签时会向src地址发送get请求获取这个图片
获取:text, code, image = captcha.generate_captcha()
redis_cli = get_redis_connection('image_code')
在该应用下新建:contant.py文件写入:MAGE_DODE_EXPIRES = 60 * 5
在视图文件中引入:from . import constants
redis_cli.setex(uuid,constants.IMAGE_CODE_EXPIRES,code)
1、客户端将手机号和图形验证码的值以及uuid发给服务器 2、服务器接收并验证 (提取图形验证码,删除redis中图形验证码,对比图形验证码)3、验证成功随机生成六位验证码 4、将验证码存入redis 5、发送短信验证码和手机号给“短信平台”,6、用户收到短信验证码。
提取图形验证码后立即删除redis中的内容,避免用户使用图形验证码恶意测试
1、 #接收
uuid = request.GET.get('image_code_id')
image_code = request.GET.get('mage_code')
2、 # 验证
if not all([uuid,image_code]):
3、redis_cli = get_redis_connection('image_code')
image_code_redis = redis_cli.get(uuid)
4、 if image_code_redis is None:
6、if image_code_redis.decode().lower() != image_code.lower():
从redis读出来的都是bytes接收的是二进制。且不区分大小写
7、 sms_code ='%06d'%random.randint(0,999999)
1、存入缓存:redis_cli = get_redis_connection('sms_code')
2、设置过期时间:redis_cli.setex = (moblie,SMS_CODE_EXPIRES,msm_code)
redis_cli = get_redis_connection('sms_code')
sms_code_redis = redis_cli.get(moblie)
if sms_code_redis is None:
return http.HttpResponseForbidden("短信验证码已过期")
if sms_code_redis != msg_code:
return http.HttpResponseForbidden("短信验证码错误")
1、redis_cli.setex(mobile + '_flag', constants.SMS_CODE_FLAG, 1) # 存一个标记,值1为多少不重要
2、# 0.是否60秒内 (键不为空)
if redis_cli.get(moblie + '_flag') is not None:
return http.JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '发送短信太频繁,请稍候再发'})
问题:当需要向redis中写入多条数据时,会与redis服务器进行多次交互
可以一次性发送多条命令并在执行完后一次性将结果返回。
pipeline通过减少客户端与Redis的通信次数来实现降低往返延时时间
1、创建管道对象:redis_pl = redis_cli.pipeline()
2、redis_pl.setex(mobile,过期时间,sms_code)
3、redis_pl.setex(mobile+'flag',过期时间,1) # 标记
关键时通过管道调用方法,而不是通过redis客户端调用方法(代码)
问题:在视图中有耗时的代码(发送短信),则用户的响应需要等待很长时间。(响应开始才倒计时)
新问题:所有的底层代码都已经被框架,如Django封装好,此时如何使用异步
主流消息队列:RabbitMQ、ActiveMQ、Kafka
worker :从队列中取任务执行,本质就是一个线程、进程、协程
1、总工程目录下创建一个包(celery_tasks)用于存放celery相关
2、在celery_tasks下新建admin | config文件
3、新建sms包用于存发短信相关
4、在sms包中新建一个名为:tasks.py文件(这个名字是固定的)
admin:
from celery import Celery
#读取django项目的配置
os.environ["DJANGO_SETTINGS_MODULE"] = "meiduo_mall.settings.dev"
# 创建celery对象
app=Celery()
# 加载可用任务
app.config_from_object("celery_task.config")
config:broker_url= 'amqp://guest:[email protected]:5672'
@apps.task(bind=True, name='send_verify_email', retry_backoff=3)
def send_verify_email(self, to_email, verify_url):
bind=True: 将任务对象作为参数传给self
Django调用一个任务,该任务会存在RabbitMQ中,celery在Rabbit中取任务
1、获取登陆界面 1、填写信息,4发送登陆请求 3、视图接收、校验、处理(状态保持)、响应
2、请求方法:POST 地址:/login/ 参数:username \password \remembered
username = reque.POST.get('username')
user = authenticate(request,username=username,password=password)
在登陆页面,用户文本框中可以添加用户名,也可以添写手机号,完成登陆。
utils--->新建authenticate 重写authentic方法
from django.contrib.auth.backends import ModelBackend
import re
from users.models import User
class MeiduoModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
if re.match(r'^1[345789]\d{9}$',username):
user = User.objects.get(moblie=username)
else:
user = User.objects.get(username=username)
except:
return None
if user.check_password(password):
return user
else:
return None
方案一:
{% if user.is_authenticated %}
显示用户名
{% else %}
显示登陆 | 注册
{% endif %}
字典取值:dict[key],key不存在时会报错。dict.get('key','/'):如果key不存在则返回‘/’
python manage.py makemigrations
1、Django认证系统:is_authenticated
request.user.is_authenticated() = True '用户登陆'
2、自定义返回JSON的login_required装饰器
在meiduo_mall.utils.views.py中
json_dict = json.loads(request.body.decode())
email = json_dict.get('email')
if not email: == if not all([email])
if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
参见: Django发送邮件的配置
request.user.email = email
request,user -->当前登陆用户
参见: 验证邮箱真实有效
位置:django.core.mail模块提供了send_mail()来发送邮件。
方法参数:
send_mail(subject, message, from_email, recipient_list, html_message=None) 普通邮件用message,内容中含有html需要使用html_message,并把message设为None
JsonResponse:如果前端请求的Ajax,使用JsonResponse返回josn数据,状态码200
HttpResponseForbidden:返回的是tex/html页面信息,状态码是403
2、在celery_tasks下创建email包用于实现发送邮件的异步任务
1、省市区模型类:class Srea(models.Model)
2、related_name = ' subs' 从表中的外键名
A-----B
1---n:多的字段定义外键
a.b_set ==a.subs
未完,待续.......