标签:dex hang ber 灰色 字典 默认 padding temp blank
美多商城商业模式:
C2B模式(消费者到企业的商业模式),相类似网站包括:京东,淘宝,海尔商城,尚品宅配等。
商城需求分析
1,用户部分
2,商品部分
3,购物车部分
4,商品订单备份
5,用户支付部分
6,上线程序的配置
基本功能:用户注册,登录,密码的重置,第三方登录
用户注册
1,图片验证码
流程分析:
1,前端生成uuid随机字符串
2,后端生成图片验证码发送给前端,将图形验证码的存入到redis中
2,短信验证码
1,检查图片的验证码
2,检验是否是在60s内是否已经发送过
3,生成短信验证码
4,保存发送的短信验证码
5,发送短信(第三方平台发送:云通讯)
3,判断用户名是否存在
1,用户输入用户名之后ajax局部刷新页面
2,后台查询数据库用户是否存在
3,返回数据给前端
4,判断手机号码是否已经存在
同3
cookies的使用目的
传统的cookies显示出来的问题
- 在现在的市场各种不同的浏览器,对同一个网站进行,用户的每种设备都需要维护相关的session在服务器端,会造成服务器资源的浪费,相关网站采取单点登录来记录用户的状态状态来解决以上传统cookies带来的问题
单点登录的概念
token认证的机制
备注:
用户登录JWT认证的的流程源代码(待继续理解)
qq登录
qq登录流程oauth2的认证流程分析
![enter description here][1]
忘记密码的功能的实现
个人信息
个人信息是用户的私有信息,必须是登录用户才可以访问,并且值可以访问自己的相关信息
用户个人中心的信息中有一项是用户的邮箱是否激活
邮箱验证的流程
from rest_framework import serializers
from .models import Area
class AreaSerializer(serializers.ModelSerializer):
"""
行政区划信息序列化器
"""
class Meta:
model = Area
fields = (‘id‘, ‘name‘)
class SubAreaSerializer(serializers.ModelSerializer):
"""
子行政区划信息序列化器
"""
subs = AreaSerializer(many=True, read_only=True)
class Meta:
model = Area
fields = (‘id‘, ‘name‘, ‘subs‘)
基本功能:提交订单,我的订单,订单评价
电商类型的网站首页的访问评率较大,每次获取首页过程中去对数据库进行查询显然不太合理,除了使用传统意义上的缓存实现之外,我们可以使用首页静态化的技术,即将动态生成的html页面生成保存成静态文件,在用户访问的过程中直接将静态文件发送给用户
优点:可以缓解数据库压力,并且可以提高用户访问的网站的速度,提高用户体验
带来的问题是:用户在页面中动态生成的部分数据如何处理
应用场景:经常容易访问但是,数据的变动并不是太大的一些页面可以考虑使用静态化技术
难点GoodsCategory,GoodsChannel两个表格之间的关系设计以及获取商城商品分类的菜单
难点 商品详情页面的数据结构
#!/usr/bin/env python
"""
功能:手动生成所有SKU的静态detail html文件
使用方法:
./regenerate_detail_html.py
"""
import sys
sys.path.insert(0, ‘../‘)
sys.path.insert(0, ‘../meiduo_mall/apps‘)
import os
if not os.getenv(‘DJANGO_SETTINGS_MODULE‘):
os.environ[‘DJANGO_SETTINGS_MODULE‘] = ‘meiduo_mall.settings.dev‘
import django
django.setup()
from django.template import loader
from django.conf import settings
from goods.utils import get_categories
from goods.models import SKU
def generate_static_sku_detail_html(sku_id):
"""
生成静态商品详情页面
:param sku_id: 商品sku id
"""
# 商品分类菜单
categories = get_categories()
# 获取当前sku的信息
sku = SKU.objects.get(id=sku_id)
sku.images = sku.skuimage_set.all()
# 面包屑导航信息中的频道
goods = sku.goods
goods.channel = goods.category1.goodschannel_set.all()[0]
# 构建当前商品的规格键
sku_specs = sku.skuspecification_set.order_by(‘spec_id‘)
sku_key = []
for spec in sku_specs:
sku_key.append(spec.option.id)
print("当前商品的规格键[1,4,7]",sku_key)
# 获取当前商品的所有SKU
skus = goods.sku_set.all()
print("获取当前商品的所在的SPU下的所有SKU对象",skus)
# 构建不同规格参数(选项)的sku字典
# spec_sku_map = {
# (规格1参数id, 规格2参数id, 规格3参数id, ...): sku_id,
# (规格1参数id, 规格2参数id, 规格3参数id, ...): sku_id,
# ...
# }
spec_sku_map = {}
for s in skus:
# 获取sku的规格参数
s_specs = s.skuspecification_set.order_by(‘spec_id‘)
# 用于形成规格参数-sku字典的键
key = []
for spec in s_specs:
key.append(spec.option.id)
# 向规格参数-sku字典添加记录
# print("构造出的不同规格的参数",key)
spec_sku_map[tuple(key)] = s.id
print("{(1, 4, 7): 1, (1, 3, 7): 2}构造出的不同规格的参数",spec_sku_map)
# 获取当前商品的规格信息
specs = goods.goodsspecification_set.order_by(‘id‘)
print("当前商品所有的规格选项,屏幕,颜色,,,",specs)
# print("sku_key",sku_key)
# 若当前sku的规格信息不完整,则不再继续
if len(sku_key) < len(specs):
return
for index, spec in enumerate(specs):
# if index == 0:
# print("index", index)
# print("GoodsSpecification的规格信息对象", spec)
# 复制当前sku的规格键
key = sku_key[:]
print("当前的规格选项",spec.name)
# 该规格的选项
options = spec.specificationoption_set.all()
print("options规格信息的选项", options)
for option in options:
# 在规格参数sku字典中查找符合当前规格的sku
print("001",key)
print("固定不变的数据库中只有这两种商品spec_sku_map",spec_sku_map)
print("option.id", option.id)
key[index] = option.id
print("002",key)
option.sku_id = spec_sku_map.get(tuple(key))
print(option.sku_id)
spec.options = options
# 渲染模板,生成静态html文件
context = {
‘categories‘: categories,
‘goods‘: goods,
‘specs‘: specs,
‘sku‘: sku
}
template = loader.get_template(‘detail.html‘)
html_text = template.render(context)
file_path = os.path.join(settings.GENERATED_STATIC_HTML_FILES_DIR, ‘goods/‘+str(sku_id)+‘.html‘)
with open(file_path, ‘w‘) as f:
f.write(html_text)
if __name__ == ‘__main__‘:
sku = SKU.objects.get(id=1)
generate_static_sku_detail_html(sku.id)
当前商品的规格键[1,4,7] [1, 4, 7]
获取当前商品的所在的SPU下的所有SKU对象 <QuerySet [<SKU: 1: Apple MacBook Pro 13.3英寸笔记本 银色>, <SKU: 2: Apple MacBook Pro 13.3英寸笔记本 深灰色>]>
{(1, 4, 7): 1, (1, 3, 7): 2}构造出的不同规格的参数 {(1, 4, 7): 1, (1, 3, 7): 2}
当前商品所有的规格选项,屏幕,颜色,,, <QuerySet [<GoodsSpecification: Apple MacBook Pro 笔记本: 屏幕尺寸>, <GoodsSpecification: Apple MacBook Pro 笔记本: 颜色>, <GoodsSpecification: Apple MacBook Pro 笔记本: 版本>]>
当前的规格选项 屏幕尺寸
options规格信息的选项 <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 屏幕尺寸 - 13.3英寸>, <SpecificationOption: Apple MacBook Pro 笔记本: 屏幕尺寸 - 15.4英寸>]>
001 [1, 4, 7]
固定不变的数据库中只有这两种商品spec_sku_map {(1, 4, 7): 1, (1, 3, 7): 2}
option.id 1
002 [1, 4, 7]
1
001 [1, 4, 7]
固定不变的数据库中只有这两种商品spec_sku_map {(1, 4, 7): 1, (1, 3, 7): 2}
option.id 2
002 [2, 4, 7]
None
当前的规格选项 颜色
options规格信息的选项 <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 颜色 - 深灰色>, <SpecificationOption: Apple MacBook Pro 笔记本: 颜色 - 银色>]>
001 [1, 4, 7]
固定不变的数据库中只有这两种商品spec_sku_map {(1, 4, 7): 1, (1, 3, 7): 2}
option.id 3
002 [1, 3, 7]
2
001 [1, 3, 7]
固定不变的数据库中只有这两种商品spec_sku_map {(1, 4, 7): 1, (1, 3, 7): 2}
option.id 4
002 [1, 4, 7]
1
当前的规格选项 版本
options规格信息的选项 <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/256G存储>, <SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/128G存储>, <SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/512G存储>]>
001 [1, 4, 7]
固定不变的数据库中只有这两种商品spec_sku_map {(1, 4, 7): 1, (1, 3, 7): 2}
option.id 5
002 [1, 4, 5]
None
001 [1, 4, 5]
固定不变的数据库中只有这两种商品spec_sku_map {(1, 4, 7): 1, (1, 3, 7): 2}
option.id 6
002 [1, 4, 6]
None
001 [1, 4, 6]
固定不变的数据库中只有这两种商品spec_sku_map {(1, 4, 7): 1, (1, 3, 7): 2}
option.id 7
002 [1, 4, 7]
1
specs = [
{
‘name‘: ‘屏幕尺寸‘,
‘options‘: [
{‘value‘: ‘13.3寸‘, ‘sku_id‘: xxx},
{‘value‘: ‘15.4寸‘, ‘sku_id‘: xxx},
]
},
{
‘name‘: ‘颜色‘,
‘options‘: [
{‘value‘: ‘银色‘, ‘sku_id‘: xxx},
{‘value‘: ‘黑色‘, ‘sku_id‘: xxx}
]
},
...
]
specs = [
{
‘name‘: ‘屏幕尺寸‘,
‘options‘: [
{‘value‘: ‘13.3寸‘, ‘sku_id‘: Iphone7的sku_id},
{‘value‘: ‘15.4寸‘, ‘sku_id‘: Iphone6的sku_id},
{‘value‘: ‘15.4寸‘, ‘sku_id‘: Iphone7的sku_id2},
]
},
{
‘name‘: ‘颜色‘,
‘options‘: [
{‘value‘: ‘银色‘, ‘sku_id‘: Iphone7的sku_id},
{‘value‘: ‘银色‘, ‘sku_id‘: Iphone6的sku_id},
{‘value‘: ‘金色‘, ‘sku_id‘: Iphone7的sku_id2},
]
},
...
]
前端通过传入的sku id来取值生成的详情页面,从同一份数据数据中拿的值,就会避免重复,例如Iphone6的只是取出所有的Iphone6的所有的信息生成静态页面,传入的sku id不同得到的页面效果不同,通过不同的id也可以找到不同的商品的详情页面
细节完善在运营人员相关修改商品信息,要在后端实现,自动刷新详情的页面的数据,自动触发静态页面的生成,利用了django中的ModelAdmin,在数据发生变动之后自动进行更新相关数据
class SKUSpecificationAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
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, request, 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)
class CartMixin():
def str2dict(self, redis_data): # redis_data从redis中读取的数据
""" 转化为python字典"""
redis_dict = pickle.loads(base64.b64decode(redis_data))
return redis_dict
def dict2str(self, redis_dict):
""" python中dict转为可以存入redis中的数据"""
# 将合并后的字典再次存入到redis中
redis_bytes = pickle.dumps(redis_dict)
redis_str = base64.b64encode(redis_bytes)
return redis_str
def write_cart(self, request: Request, response: Response, cart_dict: dict):
""" 写购物车数据"""
cart_str = self.dict2str(cart_dict)
if request.user.is_authenticated:
key = "cart2_%s" % request.user.id
get_redis_connection("cart").set(key, cart_str)
else:
response.set_cookie("cart", cart_str)
def read_from_redis(self, user_id):
""" 返回一个字典"""
key = "cart2_%s" % user_id
redis_data = get_redis_connection("cart").get(key)
if redis_data is None:
return {}
return self.str2dict(redis_data)
def read_from_cookie(self, request: Request):
value = request.COOKIES.get("cart")
if value is None:
return {}
return self.str2dict(value)
def read(self, request: Request) -> dict:
if request.user.is_authenticated:
cart_dict = self.read_from_redis(request.user.id)
else:
cart_dict = self.read_from_cookie(request)
return cart_dict
class CartView(CartMixin, APIView):
# pagination_class = StandardResultsSerPagination
def post(self, request):
serializer = CartSerializer(data=request.data) # 检查前端发送过来数据是否正确
serializer.is_valid(raise_exception=True) # 数据检验通过
sku_id = serializer.validated_data[‘sku_id‘]
count = serializer.validated_data[‘count‘]
selected = serializer.validated_data["selected"]
cart_dict = self.read(request)
if sku_id in cart_dict:
#
new_count = cart_dict[sku_id][0] + count
cart_dict[sku_id] = [new_count, selected]
else:
cart_dict[sku_id] = [count, selected]
resp = Response(serializer.data, status=status.HTTP_201_CREATED)
self.write_cart(request, resp, cart_dict)
return resp
def get(self, request):
cart_dict = self.read(request)
skus = SKU.objects.filter(id__in=cart_dict.keys())
for sku in skus:
sku.count = cart_dict[sku.id][0]
sku.selected = cart_dict[sku.id][1]
serializer = CartSKUSerializer(skus, many=True)
return Response(serializer.data)
def put(self, request):
# 检查前端发送的数据是否正确
serializer = CartSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
sku_id = serializer.validated_data.get(‘sku_id‘)
count = serializer.validated_data.get(‘count‘)
selected = serializer.validated_data.get(‘selected‘)
cart_dict = self.read(request)
cart_dict[sku_id] = [count, selected]
resp = Response(serializer.data, status=status.HTTP_201_CREATED)
self.write_cart(request, resp, cart_dict)
return resp
def delete(self, request):
# 检查参数sku_id
serializer = CartDeleteSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
sku_id = serializer.validated_data[‘sku_id‘]
cart_dict = self.read(request)
if sku_id in cart_dict:
del cart_dict[sku_id]
resp = Response(serializer.data, status=status.HTTP_204_NO_CONTENT)
self.write_cart(request, resp, cart_dict)
return resp
def merge_cart_cookie_to_redis(request, response, user):
""" 合并购物车"""
cookies_cart = request.COOKIES.get(‘cart‘)
if cookies_cart is not None:
cookies_dict = pickle.loads(base64.b64decode(cookies_cart)) # 取出cookies中的数据
print("cookies_dict000", cookies_dict)
redis_conn = get_redis_connection("cart")
redis_cart = redis_conn.get("cart2_%s" % user.id) #
redis_dict = {}
if redis_cart:
redis_dict = pickle.loads(base64.b64decode(redis_cart)) # 取出的是redis中的数据
print("redis_dict001", redis_dict)
# 过滤购物车中没有被选中的商品
new_cookies_dict = deepcopy(cookies_dict)
for sku_id, value in cookies_dict.items():
if not value[1]:
new_cookies_dict.pop(sku_id)
print("redis_dict002", new_cookies_dict)
# 合并cookies中的值
redis_dict.update(new_cookies_dict)
print("redis_dict003", redis_dict)
redis_str = base64.b64encode(pickle.dumps(redis_dict))
key = "cart2_%s" % user.id
get_redis_connection("cart").set(key, redis_str)
# 往redis中写入数据
# if cart:
# pl = redis_conn.pipeline()
# pl.hmset("cart_%s" % user.id, cart)
# pl.sadd("cart_selected_%s" % user.id, *redis_cart_selected)
# pl.execute()
# 删除cookie中的数据
response.delete_cookie("cart")
return response
return response
基本功能:支付宝支付流程分析
标签:dex hang ber 灰色 字典 默认 padding temp blank
原文地址:https://www.cnblogs.com/cerofang/p/9457875.html