Django3.x版本,开发部署

Python 投稿 59700 0 评论

Django3.x版本,开发部署

前言

项目完成 - 基于Django3.x版本 - 开发部署小结

进入正题

本文继续记录Django项目开发的一些经验。

DjangoStarter项目模板来开发,该项目模板(脚手架)整合了一些常用的第三方库以及配置,内置代码生成器,只要专注业务逻辑实现即可。

数据批量导入

先把的实例全都添加到列表里面,然后再批量导入,就很快了。

result = data_proc()
data = []

for item in result:
    print(f"处理:{item['name']}")
    data.append(ModelObj(name=item['name']))
    
print('正在批量导入')
ModelObj.objects.bulk_create(data)
print('完成')

还有除了这个批量新增的API,DjangoORM还支持批量更新,,用法同这个批量新增。

数据处理

而且这些数据还涉及到多个表,这就导致了数据处理和导入速度异常缓慢

所以后面来的新一批数据,我选择自己来搞,SQL还是不太适合做这些数据清洗~

这次新需求给的Excel很恶心,里面一堆合并的单元格,虽然是好看,但要导入数据库很麻烦啊!

数据例子如下

不过我们可以用pandas的数据补全功能来处理。

import pandas as pd

xlsx1 = pd.ExcelFile('文件名.xlsx')
# 参数0代表第一个工作表,header=0代表第一行作为表头,uescols表示读取的列范围,我们不要第一列那个序号
df = pd.read_excel(xlsx1, 0, header=0, usecols='B:G')

df['姓名'].fillna(method='pad', inplace=True)
df['性别'].fillna(method='pad', inplace=True)
df['出生年月'].fillna(method='pad', inplace=True)
df['联系人'].fillna(method='pad', inplace=True)
df['联系电话'].fillna(method='pad', inplace=True)

代码里有注释,用填充缺失的字段即可

json_str = df.to_json(orient='records')
parsed = json.loads(json_str)

这样出来就是键值对的数据了

参考资料

admin后台优化

本项目的admin界面基于simpleUI库定制

然后图标用的font-awesome,图表用的是chart.js,都属于是看看文档就会用的组件,官网文档地址我都整理在下面了,自取~

在SimpleUI里,自定义的主页是以iframe的形式实现的!而SimpleUI本身是Vue+ElementUI,所以想要在主页里跳转到admin本身的其他页面是很难实现的!这点要了解,我暂时没想到什么好的办法,要不下次试试别的admin主题好了~

参考资料

继续说Django的聚合查询

  • aggregate

  • annotate

  • values

  • values_list

根据我目前的理解,和的第一个区别是,前者返回dict,后者返回queryset,可以继续执行其他查询操作。

aggregate

统计用户的男女数量

from django.db.models import Count

result1 = User.objects.filter(gender='男').aggregate(male_count=Count('pk', distinct=True))
result2 = User.objects.filter(gender='女').aggregate(female_count=Count('pk', distinct=True))

PS:其实这里的函数里,可以不加参数的,毕竟主键()应该是不会重复的

# result1
{
    "male_count": 100
}

# result2
{
    "female_count": 100
}

应该很容易理解

annotate

from django.db.models import Count

result1 = User.objects.values('gender').annotate(count=Count('pk'))

返回结果

[
    {
        "gender": "男",
        "count": 100
    },
    {
        "gender": "女",
        "count": 100
    }
]

简而言之,就是在分组之后,对数据进行聚合运算之后把自定义的字段插入每一组内~ 有点拗口,反正看上面的代码就好理解了。

values / values_list

(这俩都跟分组有关)

id name gender country
1 人1 中国
2 人2 越南
3 人3 新加坡
4 人4 马来西亚
5 人5 中国
6 人6 中国

我们可以用这段代码提取所有国家

User.objects.values("country")
# 或者
User.objects.values_list("country")

前者根据指定的字段分组后返回包含字典的

<QuerySet [{'country': '中国'}, {'country': '越南'}, {'country': '新加坡'}, {'country': '马来西亚'}, {'country': '中国'}, {'country': '中国'}]>

后者返回的是包含元组的

<QuerySet [('中国',), ('越南',), ('新加坡',), ('马来西亚',), ('中国',), ('中国',)]>

然后还能加一个参数,直接返回包含数组的

<QuerySet ['中国', '越南', '新加坡', '马来西亚', '中国', '中国']>

这就可以很直观的看出来这俩函数的作用了。

User.objects.values("country").annotate(people_count=Count('pk'))

结果大概是这样

[
    {
        "country":  "中国",
        "people_count": 3
    },
    {
        "country":  "越南",
        "people_count": 1
    },
    {
        "country":  "新加坡",
        "people_count": 3
    },
    {
        "country":  "马来西亚",
        "people_count": 3
    }
]

搞定~

参考资料

使用docker部署MySQL数据库

虽然之前看到有人说MySQL不适合用docker来部署,不过docker实在方便,优点掩盖了缺点,所以本项目还是继续使用docker。

首先如果在本地启动一个测试用的MySQL,可以找个空目录,单独创建一个文件,配置内容在下面,然后运行。

version: "3"
services:
  mysql:
    image: daocloud.io/mysql
    restart: always
    volumes:
      - ./mysql-data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=mysql-admin
      - MYSQL_USER=test
      - MYSQL_PASS=yourpassword
    ports:
      - "3306:3306"

使用开启端口,方便我们使用Navicat等工具连接数据库操作。

version: "3"
services:
  mysql:
    image: daocloud.io/mysql
    restart: always
    volumes:
      - ./mysql-data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=mysql-admin
    # 注意这里使用expose而不是ports里,这是暴露端口给其他容器使用,但docker外部就无法访问了
    expose:
      - 3306
  web:
    restart: always # 除正常工作外,容器会在任何时候重启,比如遭遇 bug、进程崩溃、docker 重启等情况。
    build: .
    command: uwsgi uwsgi.ini
    volumes:
      - .:/code
    ports:
      - "80:8000"
    # 在依赖这里指定mysql容器,然后才能连接到数据库
    depends_on:
      - mysql

关键的配置我写了注释,很好懂。

参考资料

关于缓存问题

比如说下面这两个地址,虽然是指向同一个接口,但参数不同,按理说应该返回不同的数据。

性能优化

老生常谈…

经过profile性能分析,瓶颈基本都在哪些统计类的接口,这类接口的特征就是要关联多个表查询,经常一个接口内需要多次请求数据库,所以优化思路就很明确了,减少数据库请求次数。

  • 一种是一次性把数据全部取出到内存,然后用pandas这类数据分析库来做聚合处理;

  • 一种是做先做预计算,然后保存中间结果,下次请求接口的时候直接去读取中间结果,把中间结果拿来做聚合

最终我选择使用第二种方式,并且选择把中间结果存在MongoDB数据库里

小结

团队的话,我们这的领导属于是不太了解技术那种,然后抗压能力比较差,平时任务不紧急的时候就不怎么干扰我们的进度,在项目比较急的情况下就乱套了,瞎指挥、乱提需求、乱干扰进度,总之就是添乱拖后腿…

实际上一个政企项目涉及到太多非技术因素了,其实这本不是咱技术人员需要关心的,但现实就是这样,唉。

编程笔记 » Django3.x版本,开发部署

赞同 (91) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽