day13订单管理平台项目【知识点总结】
【day13】#
自增与主键#
在django中定义表时会自动生成id列,其字段类型如下
在settings.py
文件中的最后一行是DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
,其定义的就是id的字段类型。其中Auto
表示自增,其中参数primary_key默认为True(设置id为主键)
如果不希望使用django内置提供的这个id,也是可以自定义的,方式如下
抽象类【逻辑删除】#
逻辑删除:为了防止敏感数据丢失,使用逻辑删除。定义抽象类ActiveBaseModel,定义字段active为1或0来表示数据状态(存在/已删除),其他类继承该抽象类,继承active字段,后续操作根据active字段即可。例:删除时只需将active更新为0;查找时加上filter(active=1)即可查找已存在数据等
订单表【注意】#
在生成订单记录的时候,多写一个price记录价格,而不用商品价格表的price,以防止以后更改商品价格造成的订单记录中价格的更改
索引【优化】#
db_index#
索引
对于需要频繁查询的字段,给字段加上索引,可以增加查询速度。
实现:会给加索引的该字段生成一个文件,这个文件会按照指定算法(哈希,B+Tree)存储该字段。这种存储方式增加了查询速度。
不能给所有字段都加索引,生成文件太多...
unique#
唯一索引
功能:查询速度快+唯一约束
DecimalField#
十进制小数,解决小数不精准
像金额类小数建议用DecimalField
字段(十进制小数)存储,完全精准。
浮点数不精准原因:0.1 0.2小数在计算机中是以二进制存储的0.0001100110011... 0.001100110011...
计算机内存有限,无法存储无限位的二进制数,只能截取一定的位数来近似表示
详细
计算机浮点数不精准主要是由其存储和运算机制导致的,以下以 0.1 + 0.2
为例进行讲解:
- 十进制小数转二进制的限制:十进制的0.1和0.2转换为二进制时,会得到无限循环的二进制数。0.1转换为二进制是
0.0001100110011...
(循环节是1100),0.2转换为二进制是0.001100110011...
(循环节也是1100)。但计算机内存有限,无法存储无限位的二进制数,只能截取一定的位数来近似表示,这就产生了误差。 - 浮点数运算过程中的误差积累:在计算
0.1 + 0.2
时,计算机先将0.1和0.2的近似二进制数进行加法运算,得到的结果也是一个二进制数。由于之前的近似表示已经存在误差,在加法运算过程中,这些误差可能会进一步积累。 - 结果的舍入误差:得到的二进制结果再转换回十进制进行显示时,也可能存在舍入误差。最终,
0.1 + 0.2
的计算结果在计算机中不是精确的0.3,而是0.30000000000000004
等类似的近似值。
级联删除#
on_delete=models.CASCADE
Django之Model操作:https://www.cnblogs.com/wupeiqi/articles/6216618.html
PostiveIntegerField & help_text参数#
分库分表#
有同学问:老师我数据库中的表应该有多少列?
老师:不建议太多。在设定表结构时,尽量把经常去查询的放到一张表里面,不经常查询的通过OneToOne的机制可以给它拆到另外一张表,这就是为什么数据库里边会有那个叫分库分表
分为
- 垂直分表
- 水平分表:防止过多的列降低查询速度
比如说我们呃,这个垂直方向的就相当于你表里边有300万条数据或500万条数据太多了,对吧?那你说我再把这个表分成两张表。一个是一个放100万对吧?另外一个放200万就这样,其实是可以的。也可以在水平方向,比如说你的表列太多了,你查询的时候速度肯定比较慢。刚才我们说比如说有60多个列。你想想,如果你有60多列,比如说你在进行查询的时候,它会把这60多列的数据全拿到。
水平分表示例
案例
缓存和Session#
django缓存默认为本机缓存,需重写CACHE
变量为redis的缓存配置
Session默认存储是数据库SESSION_ENGINE = "django.contrib.sessions.backends.db"
,需该为SESSION_ENGINE = "django.contrib.sessions.backends.cache"
global_settings.py
文件
############
# SESSIONS #
############
# Cache to store session data if using the cache session backend.
SESSION_CACHE_ALIAS = "default"
# Cookie name. This can be whatever you want.
SESSION_COOKIE_NAME = "sessionid"
# Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
# A string like "example.com", or None for standard domain cookie.
SESSION_COOKIE_DOMAIN = None
# Whether the session cookie should be secure (https:// only).
SESSION_COOKIE_SECURE = False
# The path of the session cookie.
SESSION_COOKIE_PATH = "/"
# Whether to use the HttpOnly flag.
SESSION_COOKIE_HTTPONLY = True
# Whether to set the flag restricting cookie leaks on cross-site requests.
# This can be 'Lax', 'Strict', 'None', or False to disable the flag.
SESSION_COOKIE_SAMESITE = "Lax"
# Whether to save the session data on every request.
SESSION_SAVE_EVERY_REQUEST = False
# Whether a user's session cookie expires when the web browser is closed.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
# The module to store session data
SESSION_ENGINE = "django.contrib.sessions.backends.db"
# Directory to store session files if using the file session module. If None,
# the backend will use a sensible default.
SESSION_FILE_PATH = None
# class to serialize session data
SESSION_SERIALIZER = "django.contrib.sessions.serializers.JSONSerializer"
#########
# CACHE #
#########
# The cache backends to use.
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
}
}
CACHE_MIDDLEWARE_KEY_PREFIX = ""
CACHE_MIDDLEWARE_SECONDS = 600
CACHE_MIDDLEWARE_ALIAS = "default"
默认情况下django引擎不支持连接redis,需下载django-redis
这个第三方模块
1.下载django-redis
模块
pip install django-redis
2.配置缓存
settings.py
中更改django缓存为redis并配置redis(以下写代码会覆盖django默认的CACHES
变量,所以复制以下代码就可以更改并配置)
#########
# CACHE #
#########
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)
}
}
}
3.配置Session
############
# 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"
4.测试
此时也可以手动操作,将数据保存到redis中:
from django_redis import get_redis_connection
conn = get_redis_connection("default")
conn.set("xx","123123")
conn.get("xx")
动态菜单#
介绍:动态菜单指的是不同用户登录进入后看到的是不同的菜单界面
实现思路
- v1:写两套html,一套是管理员,一套是用户,通过if判断
- v2:在
settings.py配置文件
中定义动态菜单,对于html只需更换局部菜单名称和菜单url(采用) - v3:将动态菜单的定义放入数据库中,这样不需要重启(停止)项目,就可以修改动态菜单
动态菜单-思路
人话:不同类型的用户登录,看到不同的菜单。
类型:管理员、客户
菜单:
- v1版本(管理员,客户分开写)
<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>
- v2版本【项目】(本次项目使用)
- 在settings.py配置文件中定义客户和管理员对应菜单
ADMIN = [
{
"title":"客户管理",
'children':[
{"title":"用户管理", ,name="x1"},,
{"title":"订单中心", ,name="x2"},
{"title":"交易管理", ,name="x3"},,
]
},
{
"title":"客户管理",
'children':[
{"title":"用户管理", ,name="x1"},,
{"title":"订单管理", ,name="x2"},
{"title":"交易管理", ,name="x3"},,
]
}
]
CUSTOMER = [
...
]
- 页面读取+循环展示
- v3版本(将菜单转换为表存到数据库中,不需要重启项目,可以动态修改菜单)
- 数据库表 -> 转换成字典结构
- 页面读取+循环展示
好处:动态的修改菜单,不需要重启生效。
默认选中+默认展开的问题:
在生成标签时,判断当前访问的是那个地址?与那个菜单可以对应上 class="active" => 蓝色边框。
<a href="/xxx/x">用户管理</a>
<a href="/xxx/x" class="active">级别管理</a>
<a href="/xxx/x">级别管理</a>
展示默认携带定义的样式。
如何判断?
- 当用户访问某个 /my/info/ 网址,先做路由匹配 -> request.match_resolver.name = "x3"
- 循环配置文件生成HTML标签
{"title":"用户管理", ,name="x1"},, <a href="/xxx/x">xxx管理</a>
{"title":"用户管理", ,name="x2"},, <a href="/xxx/x">xxx管理</a>
{"title":"用户管理", ,name="x3"},, <a href="/xxx/x" class='active'>xxx管理</a>
...
分离配置文件#
settings.py通用配置 + local_settings.py(区分本地和线上配置)
分离配置文件local_settings.py
- settings.py
- 本地开发,连接本地开发数据库 or 缓存。
- 线上部署,将代码上传至服务器 + 线上服务器IP密码等。
- settings.py + local_settings.py模块
- 本地开发,settings.py通用配置 + local_settings.py本地配置。
- 线上部署,将剔除local_settings.py代码上传至服务器settings.py通用配置 + local_settings.py线上配置。
git + .gitignore文件
#############
# 引入本地配置 #
#############
try:
from .local_settings import *
except ImportError:
print("引入本地配置出错")
.gitignore
文件#
- 在.gitignore文件中写local_settings.py,会将项目中所有路径下的local_settings.py文件都忽略,包括管理目录下的文件夹中的同名文件。
- 如果只想忽略特定的一个可以使用 相对路径/绝对路径 等方法指定该文件路径
# Byte-compiled / optimized / DLL files
# pycharm
.idea/
.DS_Store
offline-script/
media/
# database migrations
*/migrations/*.py
!*/migrations/__init__.py
__pycache__/
*.py[cod]
*$py.class
# Django stuff:
*.log
local_settings.py
#*.sqlite3
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
!mdeditor/static/mdeditor/editormd/lib
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
git版本控制#
git init
git config --global user.name 'Violet_ZK'
git config --global user.email '2694551335@qq.com'
git remote origin https://gitee.com/tencent-village---beijing-g_0/order_management_platform.git
git add .
git commit -m "这里是描述信息"
git push origin master
git clone 远程仓库地址 # 克隆
git pull origin 分支 # 更新
可以用git bash执行git命令,pycharm终端也可以执行git命令(前提配置git环境变量)
密码登录#
-
更改语言:
LANGUAGE_CODE = 'zh-hans'
-
提交后保留密码:
render_value=True
-
重定向name生成url:
return redirect('home')
会根据home生成url
登录函数流程:
post进来之后
- 表单验证
- 数据库验证:先判读角色是用户还是管理员
- 保存session
- 跳转到家目录
md5加密
函数定义
"""
hashlib 模块与 MD5 哈希简介
hashlib 是 Python 内置的用于处理各种哈希算法的标准库模块,哈希算法可以将任意长度的数据转换为固定长度的哈希值,
常用于数据完整性验证、密码存储等场景。MD5 是一种较为常用的哈希算法(不过由于其安全性方面的一些局限,现在多在非安全敏感的场景使用),
它会对输入的数据生成一个 128 位(16 字节)的哈希值,通常以十六进制字符串的形式表示。
"""
import hashlib
def md5_string(data_string):
# 创建md5对象
obj = hashlib.md5("2983ghf3gq879hfas9fadsg".encode("utf-8"))
# 传入data_string进行md5加密
obj.update(data_string.encode("utf-8"))
# 返回加密后结果
return obj.hexdigest()
if __name__ == '__main__':
res = md5_string("qwe123")
print(res) # 0d29e0c6da821315a85477c77a8471d7
钩子函数中使用
def clean_password(self):
old = self.cleaned_data['password']
return md5_string(old)
短信登录#
正则使用
from django.core.validators import RegexValidator
class SmsLogin(forms.Form):
role = forms.ChoiceField(
label="角色",
choices=(("2", "客户"), ("1", "管理员"))
)
mobile = forms.CharField(
label="电话号",
validators=[RegexValidator(r'^1[3579]\d{9}$', '手机号格式错误')],
widget=forms.TextInput
)
code = forms.CharField(
label="验证码",
widget=forms.TextInput
)
作者:cloud-2-jane
出处:https://www.cnblogs.com/cloud-2-jane/p/18653747
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律