用python django框架,参与开发了一个电商物流的项目,简单说就是从用户(店主)在各个电商平台拉订单,然后智能选仓,发送订单,由仓库出货。
订单后处理功能包括:各电商平台拉取订单,检查订单(去重,留言分析,货到付款标识识别,地址合法性检查),拆单/并单,选仓发货。
辅助功能包括:允许开展营销活动(满元赠,满件赠)。允许开启消费者理智期(延迟处理订单)。全国范围智能选仓进行备货,业内叫分仓。
项目采用python django框架,涉及到下面几个技术要点:
1、以外键(Foreign Key)为关联,进行前向,后向联合查表,组合成一个QuerySet对象输出。
def get(self, user_id, order_id):
# filter方法,这是最常用的一个方法,用来取出数据库中的表项,是一个list。
order_details = OrderDetail.objects.\
filter(order_id=order_id, is_deleted=False). \
select_related('sku') # select_related是后向查表,以'sku'为外键的另一张子表,一并查出来。
order_history = OrderHistory.objects.filter(order_id=order_id)
# prefetch_related是前向查表,一并查出父表,并且可以迭加使用。
order = Order.objects.\
prefetch_related(Prefetch('order_detail', queryset=order_details, to_attr='order_details')).\
prefetch_related(Prefetch('order_history', queryset=order_history)).\
select_related('store').\
get(user_id=user_id, id=order_id)
return order #返回的order是一个django QuerySet对象。是组合了多张表构成的一个对象。
2、QuerySet对象可以多次条件过滤,从而支持多条件查询操作。
# warehouse_list是一个QuerySet对象,可以经过几个不同条件的过滤和排除,从而得到符合多条件的对象。
if 'province' in dict_arg:
warehouse_list = warehouse_list.filter(province__in=dict_arg['province'])
if 'city' in dict_arg:
warehouse_list = warehouse_list.filter(city__in=dict_arg['city'])
if 'not_approved' in dict_arg:
warehouse_list = warehouse_list.exclude(approved=dict_arg['not_approved'])
# province__in,数据库列名加上__in的意思是一个条件判断,判断province是否在=后的列表中。这是django强大之处。
3、prefetch_related另一种经典用法,关联表列名
conditions = {
"warehouseservice__code": SERVICE_ITEMS[0][0],
}
# 'warehouseservice_set'这是warehouse的一个父表的QuerySet对象。实际上django在查表时,一并把关联表全部查出来了的。
# 'warehouseservice__price'和"warehouseservice__code"是父表中的两个列名:price和code。
warehouse_list = warehouse_list.prefetch_related('warehouseservice_set')
.filter(**conditions).order_by('warehouseservice__price')
4、django排序输出
# 用order_by方法,可以对多个列名进行排序,先排第一个,第一个相同的情况下,按第二个来排。默认是升序,前面加-是降序。
warehouse_list = warehouse_list.order_by('-stars_level', 'cost_per_order')
5、http url中的query取参方法
# 前端用GET或POST方法提交时,都可以在http url中添加query参数,就是?type=1这种参数。
request.GET 类似于一个字典,更好的办法是用 request.GET.get('a', 0) 当没有传递 a 的时候默认 a 为 0
一个同事写了一个get_param_by_request(params, param_name, default_val=None, _type=None)方法来达到这个目的,
看来似乎没必要。
6、url正则表达式写法
django框架给出了一个
urlpatterns = [
# 创建直播频道、启动/停止直播
url(r'^create$', livechat_view.create, name='create_channel'),
# 发送申请看仓消息
url(r'^requests$', livechat_view.requests, name='create_or_list_requests'),
# idx是频道号,func是动作名。这两个参数都通过url给进来。这是一个技巧。
url(r'^(?P\w+)/(?P\w+)$', livechat_view.handle, name='pause_resume_delete'),
]
django的匹配url时,是从上到下来顺序执行的,如果我们把最后一行提到最前面,那创建频道和发送看仓消息就得不到正确的匹配。
7、前后台参数传递,用code而不是值,前端要展示的值,由后端查出来给前端。
OPERATION_CODE = (
(10, '创建订单', '接收订单'),
(11, '订单审核成功', '订单通过系统审核'),
(30, '仓库接单', '仓库成功接受发货任务'),
(31, '发货完成', '仓库出库完成'),
)
这个编码值,传递起来简单准确,数据量也少。当一个代码的描述值发生变化时,code仍然不用变。
8、基于ModelSerializer做序列化,返回json对象给前端。
class OrderHistorySerializer(ModelSerializer):
order_id = CharField(source='order.id')
class Meta:
model = OrderHistory
fields = [
'id', 'created_at', 'updated_at', 'order_id', 'is_system',
'operator_id', 'copy_operator_name', 'action', 'comment',
]
把要返回的字段放进去,就可以得到json化的dict返回,比较方便快捷。