2023-12-11 13:23:35 +08:00
|
|
|
|
from myapp.views.baseSQLA import MyappSQLAInterface as SQLAInterface
|
2022-08-02 16:02:22 +08:00
|
|
|
|
from flask_babel import gettext as __
|
|
|
|
|
from flask_babel import lazy_gettext as _
|
|
|
|
|
from flask_appbuilder.actions import action
|
2022-10-11 14:25:25 +08:00
|
|
|
|
from wtforms.validators import DataRequired, Length, Regexp
|
|
|
|
|
from myapp import app, appbuilder
|
2022-08-02 16:02:22 +08:00
|
|
|
|
from myapp.utils import core
|
2022-10-11 14:25:25 +08:00
|
|
|
|
from wtforms import StringField, SelectField
|
|
|
|
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget, Select2Widget
|
2023-09-03 21:15:58 +08:00
|
|
|
|
from myapp.forms import MyBS3TextAreaFieldWidget, MySelect2Widget, MyCodeArea, MySelectMultipleField
|
2022-08-02 16:02:22 +08:00
|
|
|
|
|
|
|
|
|
from .baseApi import (
|
|
|
|
|
MyappModelRestApi,
|
|
|
|
|
)
|
|
|
|
|
from flask import (
|
|
|
|
|
abort,
|
|
|
|
|
flash,
|
2022-10-10 11:44:53 +08:00
|
|
|
|
g
|
2022-08-02 16:02:22 +08:00
|
|
|
|
)
|
|
|
|
|
from .base import (
|
2022-10-10 11:44:53 +08:00
|
|
|
|
DeleteMixin
|
2022-08-02 16:02:22 +08:00
|
|
|
|
)
|
2022-10-10 11:44:53 +08:00
|
|
|
|
|
2022-08-02 16:02:22 +08:00
|
|
|
|
from myapp.models.model_metadata import Metadata_table
|
2023-09-03 21:15:58 +08:00
|
|
|
|
|
2022-08-02 16:02:22 +08:00
|
|
|
|
conf = app.config
|
|
|
|
|
|
|
|
|
|
Metadata_column_fields = {
|
2023-09-03 21:15:58 +08:00
|
|
|
|
"name": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _("列名"),
|
2022-08-16 11:09:52 +08:00
|
|
|
|
default='',
|
2023-12-11 13:23:35 +08:00
|
|
|
|
description= _('列名(小写字母、数字、_ 组成),最长50个字符'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
2023-09-03 21:15:58 +08:00
|
|
|
|
validators=[Regexp("^[a-z][a-z0-9_]*[a-z0-9]$"), Length(1, 54), DataRequired()]
|
2022-08-02 16:02:22 +08:00
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
"describe": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('列描述'),
|
2022-08-16 11:09:52 +08:00
|
|
|
|
default='',
|
2023-12-11 13:23:35 +08:00
|
|
|
|
description= _('列名描述'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
|
|
|
|
"column_type": SelectField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('字段类型'),
|
|
|
|
|
description= _('列类型'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=Select2Widget(),
|
2023-09-03 21:15:58 +08:00
|
|
|
|
choices=[['int', 'int'], ['string', 'string'], ['float', 'float']],
|
2022-08-02 16:02:22 +08:00
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
|
|
|
|
"remark": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('备注'),
|
|
|
|
|
description= _('备注'),
|
2022-08-16 11:09:52 +08:00
|
|
|
|
default='',
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
|
|
|
|
),
|
|
|
|
|
"partition_type": SelectField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('列分区类型'),
|
|
|
|
|
description= _('字段分区类型'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=Select2Widget(),
|
2023-12-11 13:23:35 +08:00
|
|
|
|
choices=[[_(x), _(x)] for x in ['主分区', "子分区", "非分区"]],
|
2022-08-02 16:02:22 +08:00
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Metadata_table_ModelView_base():
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label_title = _('元数据 表')
|
2022-08-02 16:02:22 +08:00
|
|
|
|
datamodel = SQLAInterface(Metadata_table)
|
2023-09-03 21:15:58 +08:00
|
|
|
|
base_permissions = ['can_add', 'can_show', 'can_edit', 'can_list', 'can_delete']
|
2022-08-02 16:02:22 +08:00
|
|
|
|
|
|
|
|
|
base_order = ("id", "desc")
|
2023-09-03 21:15:58 +08:00
|
|
|
|
order_columns = ['id', 'storage_cost', 'visits_seven']
|
|
|
|
|
|
|
|
|
|
add_columns = ['app', 'db', 'table', 'describe', 'field', 'warehouse_level', 'value_score', 'storage_cost',
|
|
|
|
|
'security_level', 'ttl', 'create_table_ddl']
|
|
|
|
|
show_columns = ['app', 'db', 'table', 'describe', 'field', 'warehouse_level', 'owner', 'c_org_fullname',
|
|
|
|
|
'storage_size', 'lifecycle', 'rec_lifecycle', 'storage_cost', 'visits_seven', 'recent_visit',
|
|
|
|
|
'partition_start', 'partition_end', 'status', 'visits_thirty', 'create_table_ddl',
|
|
|
|
|
'metadata_column']
|
|
|
|
|
search_columns = ['app', 'db', 'table', 'describe', 'field', 'warehouse_level', 'owner']
|
2022-08-02 16:02:22 +08:00
|
|
|
|
spec_label_columns = {
|
2023-12-11 13:23:35 +08:00
|
|
|
|
"field": _("数据域"),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edit_columns = add_columns
|
2023-09-03 21:15:58 +08:00
|
|
|
|
list_columns = ['app', 'db', 'table', 'owner', 'describe', 'field', 'warehouse_level', 'storage_cost']
|
2022-08-02 16:02:22 +08:00
|
|
|
|
cols_width = {
|
|
|
|
|
"app": {"type": "ellip2", "width": 150},
|
2023-09-03 21:15:58 +08:00
|
|
|
|
"db": {"type": "ellip2", "width": 200},
|
|
|
|
|
"table": {"type": "ellip2", "width": 300},
|
|
|
|
|
"owner": {"type": "ellip2", "width": 150},
|
2022-08-02 16:02:22 +08:00
|
|
|
|
"field": {"type": "ellip2", "width": 150},
|
|
|
|
|
"describe": {"type": "ellip2", "width": 300},
|
|
|
|
|
"warehouse_level": {"type": "ellip2", "width": 150},
|
2023-09-03 21:15:58 +08:00
|
|
|
|
"storage_cost": {"type": "ellip2", "width": 200},
|
|
|
|
|
"visits_seven": {"type": "ellip2", "width": 200},
|
|
|
|
|
"visits_thirty": {"type": "ellip2", "width": 200}
|
2022-08-02 16:02:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-18 16:01:09 +08:00
|
|
|
|
import_data = True
|
|
|
|
|
download_data = True
|
|
|
|
|
|
|
|
|
|
def pre_upload(self,data):
|
|
|
|
|
|
|
|
|
|
if not data.get('recent_visit',None):
|
|
|
|
|
data['recent_visit']=None
|
|
|
|
|
return data
|
|
|
|
|
|
2022-08-02 16:02:22 +08:00
|
|
|
|
add_form_extra_fields = {
|
2023-09-03 21:15:58 +08:00
|
|
|
|
"table": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('表名'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
default='',
|
2023-12-11 13:23:35 +08:00
|
|
|
|
description= _('数据表 格式:dwd_[产品]_[数据域]_[数据域描述]_[刷新周期d/w/m/y][存储策略i(增量)/和f(全量)] 例如,dwd_qq_common_click_di; 表名由字母数组下划线组成 '),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
2023-09-03 21:15:58 +08:00
|
|
|
|
validators=[Regexp("^[a-z][a-z0-9_]*[a-z0-9]$"), Length(1, 54), DataRequired()]
|
2022-08-02 16:02:22 +08:00
|
|
|
|
),
|
|
|
|
|
"describe": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _("描述"),
|
|
|
|
|
description='',
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
"app": SelectField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('产品'),
|
|
|
|
|
description='',
|
2023-09-03 21:15:58 +08:00
|
|
|
|
widget=MySelect2Widget(can_input=True, conten2choices=True),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
default='',
|
2023-12-11 13:23:35 +08:00
|
|
|
|
choices=[[x, x] for x in ['app1', "app2", "app3"]],
|
2022-08-02 16:02:22 +08:00
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
|
|
|
|
"db": SelectField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('数据库'),
|
|
|
|
|
description='',
|
2023-09-03 21:15:58 +08:00
|
|
|
|
widget=MySelect2Widget(can_input=True, conten2choices=True),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
choices=[[]],
|
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
2023-09-03 21:15:58 +08:00
|
|
|
|
"field": MySelectMultipleField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('数据域'),
|
|
|
|
|
description='',
|
2023-09-03 21:15:58 +08:00
|
|
|
|
widget=MySelect2Widget(can_input=True, conten2choices=True),
|
2023-12-11 13:23:35 +08:00
|
|
|
|
choices=[[x, x] for x in ['field1', "field2", "field3"]],
|
2022-08-02 16:02:22 +08:00
|
|
|
|
validators=[]
|
|
|
|
|
),
|
|
|
|
|
"security_level": SelectField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('安全等级'),
|
|
|
|
|
description='',
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=Select2Widget(),
|
2023-12-11 13:23:35 +08:00
|
|
|
|
default= _('普通'),
|
|
|
|
|
choices=[[_(x), _(x)] for x in ["普通", "机密", "秘密", "高度机密"]],
|
2022-08-02 16:02:22 +08:00
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
|
|
|
|
"value_score": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('价值评分'),
|
|
|
|
|
description='',
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
|
|
|
|
),
|
|
|
|
|
"storage_size": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('存储大小'),
|
|
|
|
|
description='',
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
|
|
|
|
),
|
|
|
|
|
"warehouse_level": SelectField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('数仓等级'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
default='TMP',
|
2023-12-11 13:23:35 +08:00
|
|
|
|
description= _('数仓等级'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=Select2Widget(),
|
|
|
|
|
choices=[["ODS",'ODS'],["DWD",'DWD'],["DWS",'DWS'],["TOPIC",'TOPIC'],['APP','APP'],["DIM",'DIM'],["TMP",'TMP']],
|
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
|
|
|
|
"storage_cost": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('数据成本'),
|
|
|
|
|
description='',
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
|
|
|
|
),
|
|
|
|
|
"owner": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('责任人'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
default='',
|
2023-12-11 13:23:35 +08:00
|
|
|
|
description= _('责任人,逗号分隔的多个用户'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=BS3TextFieldWidget(),
|
|
|
|
|
),
|
|
|
|
|
"ttl": SelectField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('保留周期'),
|
|
|
|
|
description='',
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=Select2Widget(),
|
2023-12-11 13:23:35 +08:00
|
|
|
|
default= '1 year',
|
|
|
|
|
choices=[[_(x), _(x)] for x in ["1 week", "1 month", "3 month", "6 month", "1 year", "forever"]],
|
2022-08-02 16:02:22 +08:00
|
|
|
|
validators=[DataRequired()]
|
|
|
|
|
),
|
|
|
|
|
"sql_demo": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
_('sql 示例'),
|
|
|
|
|
description= _('建表sql 示例'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=MyCodeArea(code=core.hive_create_sql_demo()), # 传给widget函数的是外层的field对象,以及widget函数的参数
|
|
|
|
|
),
|
|
|
|
|
"create_table_ddl": StringField(
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label= _('建表sql'),
|
2023-09-03 21:15:58 +08:00
|
|
|
|
# default='''
|
|
|
|
|
# -- 建表示例sql
|
|
|
|
|
# use {db_name};
|
|
|
|
|
# CREATE TABLE if not exists {table_name}(
|
|
|
|
|
# imp_date int COMMENT '统计日期',
|
|
|
|
|
# ori_log string COMMENT '原始日志',
|
|
|
|
|
# fint int COMMENT '某个数字字段'
|
|
|
|
|
# )
|
|
|
|
|
# PARTITION BY LIST(imp_date)
|
|
|
|
|
# (PARTITION default)
|
|
|
|
|
# STORED AS ORCFILE COMPRESS;
|
|
|
|
|
# '''
|
2023-12-11 13:23:35 +08:00
|
|
|
|
description= _('建表sql语句'),
|
2022-08-02 16:02:22 +08:00
|
|
|
|
widget=MyBS3TextAreaFieldWidget(rows=10)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edit_form_extra_fields = add_form_extra_fields
|
|
|
|
|
|
2024-02-28 15:03:18 +08:00
|
|
|
|
def check_edit_permission(self,item):
|
|
|
|
|
if not g.user.is_admin() and g.user.username not in item.owner:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
check_delete_permission = check_edit_permission
|
|
|
|
|
|
2023-12-11 13:23:35 +08:00
|
|
|
|
@action("muldelete", "删除", "确定删除所选记录?", "fa-trash", single=False)
|
2022-08-02 16:02:22 +08:00
|
|
|
|
def muldelete(self, items):
|
|
|
|
|
if not items:
|
|
|
|
|
abort(404)
|
|
|
|
|
for item in items:
|
|
|
|
|
try:
|
|
|
|
|
if g.user.is_admin() or (item.owner and g.user.username in item.owner):
|
|
|
|
|
self.datamodel.delete(item, raise_exception=True)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
flash(str(e), "danger")
|
|
|
|
|
|
|
|
|
|
# @pysnooper.snoop(watch_explode=('item'))
|
|
|
|
|
def pre_add(self, item):
|
|
|
|
|
# 建表
|
|
|
|
|
item.owner = g.user.username
|
2023-09-03 21:15:58 +08:00
|
|
|
|
item.node_id = item.db + "::" + item.table
|
2022-08-02 16:02:22 +08:00
|
|
|
|
item.creator = g.user.username
|
|
|
|
|
|
2024-02-28 15:03:18 +08:00
|
|
|
|
|
|
|
|
|
# # @event_logger.log_this
|
|
|
|
|
# @action("ddl", "更新远程表", "如果更新失败,请手动更改远程数据库的表结构", "fa-save", multiple=False, single=True)
|
|
|
|
|
# def ddl(self, item):
|
|
|
|
|
# pass
|
|
|
|
|
# # 自己实现更新到hive表
|
2022-08-02 16:02:22 +08:00
|
|
|
|
|
|
|
|
|
|
2023-12-11 13:23:35 +08:00
|
|
|
|
|
2023-09-03 21:15:58 +08:00
|
|
|
|
class Metadata_table_ModelView_Api(Metadata_table_ModelView_base, MyappModelRestApi, DeleteMixin):
|
2022-08-02 16:02:22 +08:00
|
|
|
|
datamodel = SQLAInterface(Metadata_table)
|
|
|
|
|
route_base = '/metadata_table_modelview/api'
|
|
|
|
|
|
|
|
|
|
# @pysnooper.snoop()
|
2022-11-23 17:01:10 +08:00
|
|
|
|
def pre_add_web(self):
|
2022-08-02 16:02:22 +08:00
|
|
|
|
self.default_filter = {
|
|
|
|
|
"owner": g.user.username
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# @pysnooper.snoop()
|
2023-09-03 21:15:58 +08:00
|
|
|
|
def pre_list_res(self, result):
|
2022-08-02 16:02:22 +08:00
|
|
|
|
data = result['data']
|
|
|
|
|
for item in data:
|
2023-09-03 21:15:58 +08:00
|
|
|
|
storage_cost = item.get('storage_cost', 0)
|
2022-08-02 16:02:22 +08:00
|
|
|
|
if storage_cost:
|
2023-09-03 21:15:58 +08:00
|
|
|
|
item['storage_cost'] = round(float(storage_cost), 6)
|
2022-11-23 17:01:10 +08:00
|
|
|
|
return result
|
2022-08-02 16:02:22 +08:00
|
|
|
|
|
|
|
|
|
# # 在info信息中添加特定参数
|
|
|
|
|
# @pysnooper.snoop()
|
2023-09-03 21:15:58 +08:00
|
|
|
|
def add_more_info(self, response, **kwargs):
|
2022-08-02 16:02:22 +08:00
|
|
|
|
pass
|
|
|
|
|
|
2023-09-03 21:15:58 +08:00
|
|
|
|
remember_columns = ['app', 'db']
|
2023-12-11 13:23:35 +08:00
|
|
|
|
label_title = _('库表')
|
2022-08-02 16:02:22 +08:00
|
|
|
|
|
|
|
|
|
|
2023-09-03 21:15:58 +08:00
|
|
|
|
appbuilder.add_api(Metadata_table_ModelView_Api)
|