day13 订单管理项目开发
1.表结构设计
1.1 abstract类
from django.db import modelsclass ActiveBaseModel(models.Model):active = models.SmallIntegerField(verbose_name="状态", default=1, choices=((1, "激活"), (0, "删除"),))class Meta:abstract = Trueclass Administrator(ActiveBaseModel):""" 管理员表 """username = models.CharField(verbose_name="用户名", max_length=32, db_index=True)password = models.CharField(verbose_name="密码", max_length=64)mobile = models.CharField(verbose_name="手机号", max_length=11, db_index=True)create_date = models.DateTimeField(verbose_name="创建日期", auto_now_add=True)
1.2 自增和主键
默认:DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
class Administrator(models.Model):""" 管理员表 """uid = models.AutoField(verbose_name="自增", primary_key=True)username = models.CharField(verbose_name="用户名", max_length=32, db_index=True)password = models.CharField(verbose_name="密码", max_length=64)mobile = models.CharField(verbose_name="手机号", max_length=11, db_index=True)create_date = models.DateTimeField(verbose_name="创建日期", auto_now_add=True)
1.3 逻辑删除
class Administrator(ActiveBaseModel):""" 管理员表 """username = models.CharField(verbose_name="用户名", max_length=32, db_index=True)password = models.CharField(verbose_name="密码", max_length=64)mobile = models.CharField(verbose_name="手机号", max_length=11, db_index=True)create_date = models.DateTimeField(verbose_name="创建日期", auto_now_add=True)active = models.SmallIntegerField(verbose_name="状态", default=1, choices=((1, "激活"), (0, "删除"),))
1.4 数据库连接
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': BASE_DIR / 'db.sqlite3',}
}
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'day06', # 数据库名字'USER': 'root','PASSWORD': 'root123','HOST': '127.0.0.1','PORT': 3307,}
}
1.5 表结构参考
from django.db import modelsclass ActiveBaseModel(models.Model):active = models.SmallIntegerField(verbose_name="状态", default=1, choices=((1, "激活"), (0, "删除"),))class Meta:abstract = Trueclass Administrator(ActiveBaseModel):""" 管理员表 """username = models.CharField(verbose_name="用户名", max_length=32, db_index=True)password = models.CharField(verbose_name="密码", max_length=64)mobile = models.CharField(verbose_name="手机号", max_length=11, db_index=True)create_date = models.DateTimeField(verbose_name="创建日期", auto_now_add=True)class Level(ActiveBaseModel):""" 级别表 """title = models.CharField(verbose_name="标题", max_length=32)percent = models.IntegerField(verbose_name="折扣", help_text="填入0-100整数表示百分比,例如:90,表示90%")def __str__(self):return self.titleclass Customer(ActiveBaseModel):""" 客户表 """username = models.CharField(verbose_name="用户名", max_length=32, db_index=True)password = models.CharField(verbose_name="密码", max_length=64)mobile = models.CharField(verbose_name="手机号", max_length=11, db_index=True)# mobile = models.CharField(verbose_name="手机号", max_length=11, db_index=True, validators=[RegexValidator(r'^\d{11}$', '手机号格式错误'), ], )balance = models.DecimalField(verbose_name="账户余额", default=0, max_digits=10, decimal_places=2)level = models.ForeignKey(verbose_name="级别", to="Level", on_delete=models.CASCADE)# level = models.ForeignKey(verbose_name="级别", to="Level", on_delete=models.CASCADE, limit_choices_to={'active': 1})create_date = models.DateTimeField(verbose_name="创建日期", auto_now_add=True)creator = models.ForeignKey(verbose_name="创建者", to="Administrator", on_delete=models.CASCADE)class PricePolicy(models.Model):""" 价格策略(原价,后续可以根据用级别不同做不同折扣)1 1000 102 2000 18"""count = models.IntegerField(verbose_name="数量")price = models.DecimalField(verbose_name="价格", default=0, max_digits=10, decimal_places=2)class Order(ActiveBaseModel):""" 订单表 """status_choices = ((1, "待执行"),(2, "正在执行"),(3, "已完成"),(4, "失败"),(5, "已撤单"),)status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=1)# 202211022123123123oid = models.CharField(verbose_name="订单号", max_length=64, unique=True)url = models.URLField(verbose_name="视频地址", db_index=True)count = models.IntegerField(verbose_name="数量")price = models.DecimalField(verbose_name="价格", default=0, max_digits=10, decimal_places=2)real_price = models.DecimalField(verbose_name="实际价格", default=0, max_digits=10, decimal_places=2)old_view_count = models.CharField(verbose_name="原播放量", max_length=32, default="0")create_datetime = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)customer = models.ForeignKey(verbose_name="客户", to="Customer", on_delete=models.CASCADE)memo = models.TextField(verbose_name="备注", null=True, blank=True)class TransactionRecord(ActiveBaseModel):""" 交易记录 """charge_type_class_mapping = {1: "success",2: "danger",3: "default",4: "info",5: "primary",}charge_type_choices = ((1, "充值"), (2, "扣款"), (3, "创建订单"), (4, "删除订单"), (5, "撤单"),)charge_type = models.SmallIntegerField(verbose_name="类型", choices=charge_type_choices)customer = models.ForeignKey(verbose_name="客户", to="Customer", on_delete=models.CASCADE)amount = models.DecimalField(verbose_name="金额", default=0, max_digits=10, decimal_places=2)creator = models.ForeignKey(verbose_name="管理员", to="Administrator", on_delete=models.CASCADE, null=True, blank=True)order_oid = models.CharField(verbose_name="订单号", max_length=64, null=True, blank=True, db_index=True)create_datetime = models.DateTimeField(verbose_name="交易时间", auto_now_add=True)memo = models.TextField(verbose_name="备注", null=True, blank=True)
2.用户认证相关
两种登录方式:
- 用户名 + 密码 登录
- 手机号 + 短信 登录
当用户登录成功后,将用户信息保存至Session【数据库 or 缓存】,不同类型用户登录 显示不同的菜单项。
2.1 发送短信
- 腾讯云短信
- 云通信短信
- 互亿无线106短信
2.2 缓存和Session
pip install django-redis
CACHES = {"default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://127.0.0.1:6379","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient","CONNECTION_POOL_KWARGS": {"max_connections": 100}"PASSWORD": "qwe123",# 'MAX_ENTRIES': 300, # 最大缓存个数(默认300)# 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)}}
}
############
# SESSIONS #
############
# Session存储在哪里?
# SESSION_ENGINE = "django.contrib.sessions.backends.db"# 如果存储到文件中,文件的路径。
# SESSION_ENGINE = "django.contrib.sessions.backends.file"
# SESSION_FILE_PATH = None# 存储到缓存
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
此时也可以手动操作,将数据保存到redis中:
from django_redis import get_redis_connectionconn = get_redis_connection("default")
conn.set("xx","123123")
conn.get("xx")
2.3 动态菜单
不同角色的用户登录,看到不同的菜单。
-
页面写死 HTML模板
<html>{% if 角色 "管理员"%}<a href="/xxx/x">用户管理</a><a href="/xxx/x">级别管理</a><a href="/xxx/x">级别管理</a>...{% else %}<a href="/xxx/x">xxx管理</a><a href="/xxx/x">级别管理</a>{% endif %} </html>
-
将菜单放在配置文件中 (选择)
# settings.pyADMIN = [{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." }, ]USER = [{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." }, ]
<html>{% if 角色 "管理员"%}{% for item in ADMIN%}<a href="{{item.url}}">{{item.title}}</a>{%emdfor%}{% else %}{% for item in USER%}<a href="{{item.url}}">{{item.title}}</a>{%emdfor%}{% endif %} </html>
如果想要显示2级菜单:
ADMIN = [{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." },{"title":"用户管理", "url":"...." },
]
ADMIN = [{"title":"用户管理", "children":[{"title":"级别列表","url":"....", "name":"level_list",}{"title":"级别列表","url":"...."}{"title":"级别列表","url":"...."}]},{"title":"订单管理", "children":[{"title":"订单列表","url":"...."}{"title":"订单列表","url":"...."}{"title":"订单列表","url":"...."}]},
]
-
菜单选中和展开
1.获取当前用户请求的 URL pricepolicy/list/ 或 url对应的name 2. pricepolicy/list/ 配置 ADMIN中的URL ->默认选中
-
路径导航的问题
1.获取当前用户请求的 URL pricepolicy/list/ 或 url对应的name 2.获取上级,展示导航信息 3.设置菜单与下级关系
2.4 权限控制
权限的判断时,要考虑:正常的点击、非法输入。
v1 = [11,22,33,44]
if 33 in v1:pass
v1 = {11,22,33,44}
if 33 in v1:pass
v1 = {11:123123,22:12312333:12312344:123123
}if 33 in v1:pass
-
文件settings.py的方式(编写)
admin_permisions = {"level_list":{...},"level_edit":{..., 'parent':'level_list'},"level_add":{... 'parent':'level_list'},"level_delete":{..'parent':'level_list'.},"user_list":{...},"user_edit":{...},"user_add":{...},"user_delete":{...}, }user_permisions = {... }
admin访问某个URL + 路由信息(name、namespace),获取当前的URL /level/edit/4/ -> 是否存在URL
在中间件中根据URL中的name进行权限的校验。
-
数据库的方式
2.5 local_settings.py
线上部署和本地settings.py想要隔离,可以使用local_settings.py来进行配置。
try:from .local_settings import *
except ImportError:pass
注意:在做版本控制提交代码时,在.gitignore中设置上 local_settings.py
2.6 用户名登录
…
2.7 短信登录
…
2.8 动态菜单
…
2.9 权限控制
…