一、项目架构
前端:
- 用户相关
- 商品相关
- 购物车相关
- 订单相关
- 后台管理
后端:
- 用户模块
- 商品模块
- 购物车模块
- 订单模块
- 后台管理模块
技术:
- mysql
- session 缓存服务器redis
- 异步任务处理celery
- 分布式文件存储系统fastdfs
二、用户认证模型
# django认证系统使用的用户模型
AUTH_USER_MODEL = "users.User"
1.类视图
将视图view以类的形式定义,通用类视图基类:
django.views.generic.View
urls.py中配置路由使用类视图的as_view()
方法,由dispatch()
方法具体将请求request分发至对应请求方式的处理方法中(get、post)等
2.django认证系统
方法名 | 备注 |
---|---|
create_user | 创建用户 |
authenticate | 登录验证 |
login | 记录登录状态 |
logout | 退出用户登录 |
is_authenticated | 判断用户是否登录 |
login_required装饰器 | 进行登录判断 |
3.django发送邮件
Django网站
---->smtp服务器
----->目的邮箱
SMTP的全程是
Simple Mail Transfer Protocol
,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP协议属于TCP/IP协议簇,它帮助每台计算机在发送获中转信件时找到下一个目的地,SMTP服务器就是遵循SMTP协议的发送邮件服务器,不同邮件服务商均有对应的smtp服务器地址,并且这个地址会提供给大家,方便大家使用Foxmail与outlook等专业邮件管理软件时可以用得上。
4.celery:异步任务队列
任务的发出者、中间人、任务的处理者可以在同一台电脑上启动,也可以不在同一台电脑上。处理者也需要任务的代码,任务处理者所在电脑必须有网
pip install celery
项目代码(任务发出者)
—发出任务—>
任务队列(中间人broker)redis
<—监听任务队列—任务处理者worker
1)使用
from celery import Celery
# 创建一个Celery类的实例对象
app = Celery('celery_tasks.tasks', broker='redis://172.16.179.130:6379/8')
2)发出任务
@app.task
def send_register_active_email(to_email, username, token):
# 发送邮件的代码
pass
# 发邮件:此方法会把发邮件的任务放到任务队列中
send_register_active_email.delay(email, username, token)
3)启动worker
celery -A celery_tasks.tasks worker -l info
5.用户激活
使用itsdangerous
加密用户身份信息
1)加密码用户身份信息
# 加密用户的身份信息,生成激活token
serializer = Serializer(settings.SECRET_KEY, 3600)
info = {'confirm':user.id}
token = serializer.dumps(info)
token = token.decode()
2)解密用户身份信息
serializer = Serializer(settings.SECRET_KEY, 3600)
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('激活连接已过期!')
6.用户登录
6.1 配置redis作为Django缓存和session后端
配置:
# Django的缓存配置
CACHES = {
"default":{
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://172.16.179.142:6379/9",
"OPTIONS":{
"CLIENT_CLASS":"django_redis.client.DefaultClient",
}
}
}
# 配置sessiong存储
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
6.2 登录判断装饰器loging_required
使用LoginRequireMixin:
from django.contrib.auth.decorators import login_required
class LoginRequiredMixin(object):
@classmethod
def as_view(cls, **initkwargs):
# 调用父类的as_view
view = super(LoginRequiredMinxin, cls).as_view(**initkwargs)
return login_required(view)
登录后跳转
# 获取登录后所需要跳转的地址
# 默认跳转到首页
next_url = request.GET.get('next', reverse('goods:index'))
# 跳转到next_url
response = redirect(next_url) # 重定向到新的地址
6.3 用户退出
logout 函数清楚登录用户的session信息
6.4 django-redis获取redis连接
from django_redis import get_redis_connection
con = get_redis_connection('default')
商品模块开发
1. 了解FastDFS分布式文件系统
集群
启动FastDFS的方法,需要的操作
- 修改如下的配置文件(在/etc/fdfs目录中)
tracker_server = ip地址:22122 - 启动tracker、storage、nginx服务:
sudo service fdfs trackerd start
sudo service fsfs storaged start
sudo /usr/local/nginx/sbin/nginx
- 执行如下命令测试是否成功
fdfs_upload_file /etc/fdfs/client.conf 要上传的图片文件
2.python对接fastdfs
- workon django_py3
- 进入fdfs_client-py-master.zip所在目录
- pip install fdfs_client-py-master.zip
3.项目上传图片和使用图片流程
海量存储,存储容量扩展方便。
文件内容重复时只保留一份。
结合nginx提高网站访问图片的效率
4. Django二次开发对接FastDFS
- 配置文件settinggs中加入如下配置
# 配置文件存储类
DEFAULT_FILE_STORAGE = 'utils.fdfs.storage.FDFSStorage'
# 配置fdfs客户端配置文件路径
FDFS_CLIENT_CONF = './utils/fdfs/client.conf'
FDFS_SERVER_URL='http://172.16.179.131:8888/'
- 创建utils/fdfs目录
- storage.py文件中自定义文件存储类
三、商品首页
- redis保存用户的购物车记录
采用的数据形式:每个用户的购物车记录用一条数据保存:
hash:
cart_用户id:{‘SKU_ID1’:数量,‘sku_id2’:数量} - 页面静态化
把原本动态的页面处理结果保存成html文件,让用户直接访问这个生成出来的静态的html页面
①使用celery生成静态页面
②配置nginx提供静态页面
③管理员修改首页所使用表中的数据时,重新生成index静态页面 - 商品搜索
搜索引擎:
1)可以对表中的某些字段进行关键词分析,简历关键词对应的索引数据。
索引:字典目录
全文检索框架:可以帮助用户使用搜索引擎。
用户----》全文检索框架haystack-----》搜索引擎whoosh
2) 搜索引擎的安装和配置
①安装python包:
pip install django-haystack
pip install whoosh
②在settings.py文件中注册应用haystack并做如下配置:
INSTALLED_APPS = (
'haystack', # 全文检索框架
)
.
.
.
.
# 全文检索框架的配置
HAYSTACK_CONNECTIONS = {
'default':{
# 使用whoosh引擎
'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
'PATH': os.path.join(BASE_DIR, 'whoosh_index')
}
}
# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
- 索引文件生成
①在goods应用目录下新建一个serach_indexes.py文件,在其中定义一个商品索引类。
class GoodsSKUIndex(indexes.SearchIndex, indexes.Indexable):
'''商品索引类'''
text = indexes.CharField(document=True, use_template=True)
def get_model(self):
return GoodsSKU
def index_queryset(self, using=None):
return self.get_model().objects.all()
②在templates下面新建目录search/indexes/goods
③在此目录下面新建一个文件goodssku_text.txt并编辑内容如下
# 制定索引的数据行
{{ object.name }}
{{ object.desc }}
{{ object.goods.detail }}
④ 使用命令生成索引文件
python manage.py rebuild_index
四、订单
mysql事务
- 事务的概念:一组mysql语句,要么执行,要么全部执行
- 事务的特点:
- 原子性:一组事务,要么成功,要么撤回
- 稳定性:有非法数据(外键约束之类),事务撤回
- 隔离性:事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度
- 可靠性:软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得,innodb_flush_log_at_trx_commit选项,决定什么时候把事务保存到日志里
- 事务控制语句
- BEGIN/START TRANSACTION:显式地开启一个事务
- COMMIT,也可以用COMMIT WORK,提交事务
- ROLLBACK,也可以用ROLLBACK WORK,回滚,撤销正在运行的所有未提交的修改。
- SAVEPOINT identifier;允许在事务中创建一个保存点
- RELEASE SAVEPOINT identifier;删除一个事务的保存点
- ROLLBACK TO identifier;把事务回滚到标记点
- mysql事务隔离级别
SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
- Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能不比其他级别好多少。读取未提交的数据,也被称之为脏读
脏读:某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
- Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是mysql默认的)。它满足了隔离的简单定义:一个事务智能看见已提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理期间可能会有新的commit,所以同一select可能返回不同结果
不可重复读(Non-replacetable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原油的数据。
- Repeatable Read(可重读)
这是mysql的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影”行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC)机制解决了该问题。
幻读(Phantom Read):在一个事务的两次查询中数据不一致,例如有一个事务查询了几行数据,而另一个事务却在此时插入了新的几行数据,先前的事务在接下来的查询中,就会发现有几行数据是它先前所没有的。
- Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。这个级别,可能导致大量的超时现象和锁竞争。
- 设置mysql事务的隔离级别
打开mysql配置文件:sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
保存配置文件,重启mysql服务:sudo service mysql restart
订单并发处理
多个用户同事请求数据库
(1)悲观锁
select * from df_goods_sku where id = 17 for update;
悲观锁获取数据时对数据进行了锁定,其他事务要想获取锁,必须等原事务结束。
(2)乐观锁
查询时不锁数据,提交更改时进行判断
update df_goods_sku set stock=0,sales=1 where id=17
冲突比较少的时候,使用乐观锁
冲突比较多的时候,使用悲观锁
五、项目部署
1.uwsgi
遵循wsgi协议的web服务器
- uwsgi的安装
pip install uwsgi - uwsgi的配置
项目部署时,需要把settings.py文件夹下的:
DEBUG=FALSE
ALLOWED_HOSTS=P['*']
[uwsgi]
#使用nginx连接时使用
#socket=127.0.0.1:8080
#直接做web服务器使用
http=127.0.0.1:8080
#项目目录
chdir=/Users/smart/Desktop/dj/bj17/dailyfresh
#项目中wsgi.py文件的目录,相对于项目目录
wsgi-file=dailyfresh/wsgi.py
processes=4
threads=2
master=True
pidfile=uwsgi.pid
daemonize=uwsgi.log
virtualenv=/Users/smart/.virtualenvs/dailyfresh
- uwsgi的启动和停止
- 启动:uwsgi–ini 配置文件路径,例如:uwsgi–ini uwsgi.ini
- 停止:uwsgi–stop uwsgi.pid路径,例如:uwsgi–stop uwsgi.pid
2.nginx
- nginx配置转发请求给uwsgi
location/{
include uwsgi_params;
uwsgi_pass_uwsgi服务器的ip:port
}
- nginx配置处理静态文件
django settings.py中配置收集静态文件路径:
STATIC_ROOT=收集的静态文件路径 例如:/var/www/dailyfresh/static;
django 收集静态文件的命令:
python manage.py collectstatic
执行上面的命令会把项目中所使用的静态文件收集到STATIC_ROOT指定的目录下。
收集完静态文件之后,让nginx提供静态文件,需要在nginx配置文件中增加如下配置:
location /static {
alias /var/www/dailyfresh/static/;
}
- nginx转发请求给另外的地址
在location对应的配置项中增加proxy_pass转发的服务器地址。
如:当用户访问127.0.0.1时,在nginx中配置把这个请求转发给172.16.179.131:80(nginx)服务器,让这台服务器提供静态首页。
location = /{
proxy_pass http://172.16.179.131;
}
9.2.4 nginx配置upstream实现负载均衡
ngnix 配置负载均衡时,在server配置的前面增加upstream配置项。
upstream dailyfresh {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
} - 部署项目流程图