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\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_iconclass SKUAdmin(object):
model_icon = 'fa fa-gift'
xadmin.site.register(models.SKU, SKUAdmin)list_displaylist_display = ['id', 'name', 'price', 'stock', 'sales', 'comments']search_fieldssearch_fields = ['id','name']list_filterlist_filter = ['category']list_editablelist_editable = ['price', 'stock']showdetailfieldsshow_detail_fields = ['name']list_export
注意,导出到xls(excel) 需要安装xlwt扩展list_export = ['xls', 'csv', 'xml']refresh_timesclass OrderAdmin(object):
list_display = ['order_id', 'create_time', 'total_amount', 'pay_method', 'status']
refresh_times = [3, 5] # 可选以支持按多长时间(秒)刷新页面data_charts
title 控制图标名称
x-field 控制x轴字段
y-field 控制y轴字段,可以是多个值
order 控制默认排序data_charts = {
"order_amount": {'title': '订单金额', "x-field": "create_time", "y-field": ('total_amount',),
"order": ('create_time',)},
"order_count": {'title': '订单量', "x-field": "create_time", "y-field": ('total_count',),
"order": ('create_time',)},
}readonly_fieldsclass SKUAdmin(object):
...
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-serverwww.meiduo.site
后端API服务器提供后端API接口python manage.py runserverapi.meiduo.site
部署阶段:
服务器作用使用域名静态文件服务器提供静态文件Nginxwww.meiduo.site
后端API服务器提供后端API接口uwsgiapi.meiduo.siteuwsgi是遵循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服务器来运行
安装uwsgipip 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;
}
}
重启nginxsudo /usr/local/nginx/sbin/nginx -s reload