项目仓库
https://github.com/EthanYan6/E-commerce-sites.git
结合代码查看笔记,效果更佳。笔记只是记录重点或者难点。
每日分享
It is time to shed the burdens of the past year and come up fresh and alive.
是时候摆脱过去一年的负担,重新焕发活力。
小闫语录:
身边总会有人问『我做xxx,什么时候开始比较好?』我的答案永远不会变『从现在开始』
做一件事,不要觉得现在时间尚早,也不要觉得为时已晚。开始做一件事的最佳的时间永远是现在。其实我们有很大一部分时间都是浪费在了犹豫上,而不是在解决问题上。考研的时候,有人会觉得都9月份了,其他人都准备半年了,我肯定比不过他们。算了,我明年再考吧......也有人会觉得都9月份了,我一定要比别人更加努力,一定要在12月份的时候赶上去,然后开始了详细的计划。只要你下定决心开始,那一刻永远不会晚。有人利用几个月时间考上了心仪的学府,也有人准备一两年仍然名落孙山。
如果你有正在犹豫的事,现在开始下定决心去做吧!
美多商城项目(十)
1.订单支付流程-支付宝
1.客户端点击支付,向服务器发送一个请求。携带订单的id。
客户端申请访问获取支付网址和参数,服务器向其返回。
2.服务器返回给客户端支付宝的支付网址和参数。
业务参数:outtradeno商户订单号;total_amout订单总金额;subject订单标题。
可选参数:returnurl同步回调地址,支付成功之后的回调地址,支付结果相关参数在回调网址后;notifyurl异步通知地址,用户完成之后,支付宝会访问此地址,然后支付宝通知商户用户支付结果。
3.客户端访问支付网址。
4.支付宝让客户端重定向访问订单支付页面。
5.客户端访问订单支付页面地址。
6.支付宝平台返回订单支付页面。
7.客户端让用户登录支付宝,选择支付方式,点击确认付款。
8.支付宝让客户端浏览器重定向访问return_url指定的地址。
9.客户端访问return_url指定的地址,服务器保存支付信息。
服务器保存支付结果相关信息
10.服务器向客户端返回支付结果。
2.支付宝支付API
2.1获取支付宝支付网址和参数
API: GET /orders/(?P<order_id>\d+)/payment/ 参数: 通过请求头,传递jwt token 通过url地址传递订单编号 响应: { "alipay_url":"支付宝支付网址和参数" }
2.1.1业务逻辑
1.需要用户登录,设置权限。
1.1获取登录用户
2.获取order_id并校验订单是否有效。
# 关键代码 order = OrderInfo.objects.get(order_id=order_id, user=user, pay_method=OrderInfo.PAY_METHODS_ENUM['ALIPAY'], status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'])
订单号是否存在;是否是此用户的订单;支付方式是否是支付宝;是否是待支付订单。
3.组织支付宝支付网址和参数。
# 构造支付宝支付链接地址 alipay = AliPay( appid="", # 开发者应用APPID app_notify_url=None, # 默认回调url app_private_key_path="", # 网站的私钥文件路径 alipay_public_key_path="", # 支付宝的公钥文件路径,验证支付宝回传消息使用,不是你自己的公钥, sign_type="RSA2", # 签名算法,RSA 或者 RSA2 debug=False # 默认False,是否使用沙箱环境 ) # 组织支付参数 # 电脑网站支付,需要跳转到https://openapi.alipaydev.com/gateway.do? + order_string total_pay = order.total_amount # Decimal order_string = alipay.api_alipay_trade_page_pay( out_trade_no=order_id, # 商户订单号 total_amount=str(total_pay), # 订单总金额 subject='美多商城%s' % order_id, # 订单标题 return_url="http://www.meiduo.site:8080/pay_success.html", # 回调地址 )
4.返回支付宝支付网址和参数。
alipay_url = settings.ALIPAY_URL + '?' + order_string return Response({"alipay_url": alipay_url})
2.2保存支付宝支付结果
API: PUT /payment/status/?<支付的结果数据> 参数: 通过请求头,传递jwt token 通过查询字符串传递支付结果数据 响应: { "trade_id": "支付交易编号" }
2.2.1业务逻辑
1.获取支付结果数据并进行签名验证。
outtradeno商户订单号
total_amount签名字符串
trade_no支付交易号
2.校验订单是否有效。
3.保存支付结果并修改订单支付状态。
4.返回应答。
3.Xadmin
Xadmin是Django的第三方扩展,比Django自带的admin站点使用方便。我们可以使用此管理站点进行网站管理。
3.1安装
通过如下命令安装xadmin的最新版
pip install https://github.com/sshwsfc/xadmin/tarball/master
在配置文件中注册如下应用
INSTALLED_APPS = [ ... 'xadmin', 'crispy_forms', 'reversion', ... ]
xadmin有建立自己的数据库模型类,需要进行数据库迁移,在数据库中建立依赖的数据表。
python manage.py migrate
在总路由中添加xadmin的路由信息
import xadmin urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'xadmin/', include(xadmin.site.urls)), ... ]
3.2使用
1.在 adminx.py
文件中注册模型。
xadmin.site.register(<模型类>)
2.定义模型Admin管理类直接继承object。
2.1站点全局配置
import xadmin from xadmin import views from goods import models class BaseSetting(object): """xadmin的基本配置""" enable_themes = True # 开启主题切换功能 use_bootswatch = True xadmin.site.register(views.BaseAdminView, BaseSetting) class GlobalSettings(object): """xadmin的全局配置""" site_title = "闫氏商城运营管理系统" # 设置站点标题 site_footer = "闫氏集团" # 设置站点的页脚 menu_style = "accordion" # 设置菜单折叠 xadmin.site.register(views.CommAdminView, GlobalSettings)
2.2站点Model管理
xadmin可以使用的页面样式控制基本与Django原生的admin一致。
list_display 控制列表展示的字段
search_fields 控制可以通过搜索框搜索的字段名称,xadmin使用的是模糊查询
list_filter 可以进行过滤操作的列
ordering 默认排序的字段
readonly_fields 在编辑页面的只读字段
exclude 在编辑页面隐藏的字段
list_editable 在列表页可以快速直接编辑的字段
showdetailfileds 在列表页提供快速显示详情信息
refresh_times 指定列表页的定时刷新
list_export 控制列表页导出数据的可选格式
data_charts 控制显示图标的样式
model_icon 控制菜单的图标
model_icon
1. class SKUAdmin(object): 2. model_icon = 'fa fa-gift' 3. 4. xadmin.site.register(models.SKU, SKUAdmin) list_display 1. list_display = ['id', 'name', 'price', 'stock', 'sales', 'comments'] search_fields 1. search_fields = ['id','name'] list_filter 1. list_filter = ['category'] list_editable 1. list_editable = ['price', 'stock'] showdetailfields 1. show_detail_fields = ['name'] list_export 注意,导出到xls(excel) 需要安装xlwt扩展 1. list_export = ['xls', 'csv', 'xml'] refresh_times 1. class OrderAdmin(object): 2. list_display = ['order_id', 'create_time', 'total_amount', 'pay_method', 'status'] 3. refresh_times = [3, 5] # 可选以支持按多长时间(秒)刷新页面
data_charts
title 控制图标名称
x-field 控制x轴字段
y-field 控制y轴字段,可以是多个值
order 控制默认排序
1. data_charts = { 2. "order_amount": {'title': '订单金额', "x-field": "create_time", "y-field": ('total_amount',), 3. "order": ('create_time',)}, 4. "order_count": {'title': '订单量', "x-field": "create_time", "y-field": ('total_count',), 5. "order": ('create_time',)}, 6. } readonly_fields 1. class SKUAdmin(object): 2. ... 3. readonly_fields = ['sales', 'comments']
3.savemodels和deletemodel。
在Django的原生admin站点中,如果想要在站点保存或删除数据时,补充自定义行为,可以重写如下方法:
save_model(self,request,obj,form,change) delete_model(self,request,obj)
而在xadmin中,需要重写如下方法:
save_models(self) delete_model(self)
在方法中,如果需要用到当前处理的模型类对象,需要通过 self.obj
来获取,如
class SKUSpecificationAdmin(object): def save_models(self): # 保存数据对象 obj = self.new_obj obj.save() # 补充自定义行为 from celery_tasks.html.tasks import generate_static_sku_detail_html generate_static_sku_detail_html.delay(obj.sku.id) def delete_model(self): # 删除数据对象 obj = self.obj sku_id = obj.sku.id obj.delete() # 补充自定义行为 from celery_tasks.html.tasks import generate_static_sku_detail_html generate_static_sku_detail_html.delay(sku_id)
4.用户管理设置需要先unregister再register。
xadmin会自动为admin站点添加用户User的管理配置
xadmin使用xadmin.plugins.auth.UserAdmin来配置
如果需要自定义User配置的话,需要先unregister(User),再添加自己的User配置并注册
import xadmin # Register your models here. from users.models import User from xadmin.plugins import auth class UserAdmin(auth.UserAdmin): list_display = ['id', 'username', 'mobile', 'email', 'date_joined'] readonly_fields = ['last_login', 'date_joined'] search_fields = ('username', 'first_name', 'last_name', 'email', 'mobile') style_fields = {'user_permissions': 'm2m_transfer', 'groups': 'm2m_transfer'} def get_model_form(self, **kwargs): if self.org_obj is None: self.fields = ['username', 'mobile', 'is_staff'] return super().get_model_form(**kwargs) xadmin.site.unregister(User) xadmin.site.register(User, UserAdmin)
5.主题切换,站点标题,页面底部标题,菜单折叠。
enable_themes = True # 开启主题切换功能 site_title = "闫氏商城运营管理系统" # 设置站点标题 site_footer = "闫氏集团" # 设置站点的页脚 menu_style = "accordion" # 设置菜单折叠
4.Django用户权限控制
用户权限控制:控制一个用户能够对哪些数据表进行哪些操作(增删改查)。
在产品运营平台中,是需要对用户进行权限控制的。Django实现了用户权限的控制。
1.消费者用户与公司内部运营用户使用一个用户数据库来存储。
2.通过is_staff 来区分是运营用户还是消费者用户。
3.对于运营用户通过is_superuser 来区分是运营平台的管理员还是运营平台的普通用户
4.对于运营平台的普通用户,通过权限、组和组外权限来控制这个用户在平台上可以操作的数据。
5.对于权限,Django会为每个数据库表提供增、删、改、查四种权限。
6.用户最终的权限为 组权限 + 用户特有权限。
5.部署
开发阶段:
服务器 | 作用 | 使用 | 域名 |
静态文件服务器 | 提供静态文件 | live-server | www.meiduo.site |
后端API服务器 | 提供后端API接口 | python manage.py runserver | api.meiduo.site |
部署阶段:
服务器 | 作用 | 使用 | 域名 |
静态文件服务器 | 提供静态文件 | Nginx | www.meiduo.site |
后端API服务器 | 提供后端API接口 | uwsgi | api.meiduo.site |
uwsgi是遵循WSGI的web服务器
5.1.静态文件
当Django运行在生产模式时,将不再提供静态文件的支持,需要将静态文件交给静态文件服务器。
我们先收集所有静态文件。项目中的静态文件除了我们使用的frontendpc中之外,django本身还有自己的静态文件,如果rest_framework、xadmin、admin、ckeditor等。我们需要收集这些静态文件,集中一起放到静态文件服务器中。
我们要将收集的静态文件放到frontendpc目录下的static目录中,所以先创建目录static。
Django提供了收集静态文件的方法。先在配置文件中配置收集之后存放的目录
STATIC_ROOT = os.path.join(os.path.dirname(os.path.dirname(BASE_DIR)), 'front_end_pc/static')
然后执行收集命令
python manage.py collectstatic
我们使用Nginx服务器作为静态文件服务器
打开Nginx的配置文件
sudo vim /usr/local/nginx/conf/nginx.conf
在server部分中配置
server { listen 80; server_name www.meiduo.site; location / { root /home/python/Desktop/front_end_pc; index index.html index.htm; } # 余下省略 }
重启Nginx服务器
sudo /usr/local/nginx/sbin/nginx -s reload
首次启动nginx服务器
sudo /usr/local/nginx/sbin/nginx
停止nginx服务器
sudo /usr/local/nginx/sbin/nginx -s stop
5.2.动态接口
在项目中复制开发配置文件dev.py 到生产配置prod.py
修改配置文件prod.py中
DEBUG = True ALLOWED_HOSTS = [..., 'www.meiduo.site'] # 添加www.meiduo.site CORS_ORIGIN_WHITELIST = ( '127.0.0.1:8080', 'localhost:8080', 'www.meiduo.site:8080', 'www.meiduo.site', # 添加 )
修改wsgi.py文件
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Ethanyan_mall.settings.prod")
django的程序通常使用uwsgi服务器来运行
安装uwsgi
pip install uwsgi
在项目目录/Ethanyan_mall下创建uwsgi配置文件 uwsgi.ini
[uwsgi] #使用nginx连接时使用,Django程序所在服务器地址 socket=127.0.0.1:8001 #直接做web服务器使用,Django程序所在服务器地址 #http=127.0.0.1:8001 #项目目录 chdir=/Users/delron/Desktop/E-commerce-sites/Ethanyan_mall #项目中wsgi.py文件的目录,相对于项目目录 wsgi-file=Ethanyan_mall/wsgi.py # 进程数 processes=4 # 线程数 threads=2 # uwsgi服务器的角色 master=True # 存放进程编号的文件 pidfile=uwsgi.pid # 日志文件,因为uwsgi可以脱离终端在后台运行,日志看不见。我们以前的runserver是依赖终端的 daemonize=uwsgi.log # 指定依赖的虚拟环境 virtualenv=/Users/smart/.virtualenvs/djagno_py3
启动uwsgi服务器
uwsgi --ini uwsgi.ini
注意如果想要停止服务器,除了可以使用kill命令之外,还可以通过
uwsgi --stop uwsgi.pid
修改Nginx配置文件,让Nginx接收到请求后转发给uwsgi服务器
upstream meiduo { server 10.211.55.2:8001; # 此处为uwsgi运行的ip地址和端口号 # 如果有多台服务器,可以在此处继续添加服务器地址 } #gzip on; server { listen 8000; server_name api.meiduo.site; location / { include uwsgi_params; uwsgi_pass meiduo; } } server { listen 80; server_name www.meiduo.site; #charset koi8-r; #access_log logs/host.access.log main; location /xadmin { include uwsgi_params; uwsgi_pass meiduo; } location /ckeditor { include uwsgi_params; uwsgi_pass meiduo; } location / { root /home/python/Desktop/front_end_pc; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
重启nginx
sudo /usr/local/nginx/sbin/nginx -s reload