造个Python轮子,实现根据Excel生成icode9
作者:互联网
前言
最近遇到一个需求,有几十个Excel,每个的字段都不一样,然后都差不多是第一行是表头,后面几千上万的数据,需要把这些Excel中的数据全都加入某个已经上线的Django项目
这就需要每个Excel建个表,然后一个个导入了
这样的效率太低,不能忍
所以我造了个自动生成 Model 和导入脚本的轮子
思路
首先拿出 pandas,它的 DataFrame 用来处理数据很方便
pandas 加载 Excel 之后,提取表头,我们要通过表头来生成数据表的字段。有些 Excel 的表头是中文的,需要先做个转换。
一开始我是想用翻译API,全都翻译成英文,不过发现免费的很慢有限额,微软、DeepL都要申请,很麻烦。索性用个拼音转换库,全都转换成拼音得了~
然后字段的长度也要确定,或者全部用不限制长度的 TextField
权衡一下,我还是做一下字段长度判定的逻辑,遍历整个表,找出各个字段最长的数据,然后再加一个偏移量,作为最大长度。
接着生成 Model 类,这里我用 jinja2 模板语言,先把大概的模板写好,然后根据提取出来的字段名啥的生成。
最后生成 admin 配置和导入脚本,同理,也是用 jinja2 模板。
实现
简单介绍下思路,现在开始上代码。
就几行而已,Python很省代码~
模型
首先定义俩模型
字段模型
class Field(object):
def __init__(self, name: str, verbose_name: str, max_length: int = 128):
self.name = name
self.verbose_name = verbose_name
self.max_length = max_length
def __str__(self):
return f'<Field>{self.name}:{self.verbose_name}'
def __repr__(self):
return self.__str__()
Model模型
为了符合Python关于变量的命名规范,snake_name
属性是用正则表达式实现驼峰命名转蛇形命名
class Model(object):
def __init__(self, name: str, verbose_name: str, id_field: Field, fields: List[Field]):
self.name = name
self.verbose_name = verbose_name
self.id_field = id_field
self.fields: List[Field] = fields
@property
def snake_name(self):
import re
pattern = re.compile(r'(?<!^)(?=[A-Z])')
name = pattern.sub('_', self.name).lower()
return name
def __str__(self):
return f'<Model>{self.name}:{self.verbose_name}'
def __repr__(self):
return self.__str__()
代码模板
使用 jinja2 实现。
本身 jinja2 是 Flask、Django 之类的框架用来渲染网页的。
不过单独使用的效果也不错,我的 DjangoStarter 框架也是用这个 jinja2 来自动生成 CRUD 代码~
Model模板
# -*- coding:utf-8 -*-
from django.db import models
class {{ model.name }}(models.Model):
"""{{ model.verbose_name }}"""
{% for field in model.fields -%}
{{ field.name }} = models.CharField('{{ field.verbose_name }}', default='', null=True, blank=True, max_length={{ field.max_length }})
{% endfor %}
class Meta:
db_table = '{{ model.snake_name }}'
verbose_name = '{{ model.verbose_name }}'
verbose_name_plural = verbose_name