194 lines
7.3 KiB
Python
194 lines
7.3 KiB
Python
|
|
import copy
|
|||
|
|
import uuid
|
|||
|
|
from django.apps import apps
|
|||
|
|
from django.core.validators import ValidationError
|
|||
|
|
from django.db import models
|
|||
|
|
from django.db.models import ManyToManyRel
|
|||
|
|
from dependency.base.utils import get_models_field_detail, get_app_info, judge_the_same, \
|
|||
|
|
judge_diff_be_two_models_and_change, table_exists, build_serializers, install_model
|
|||
|
|
from django.core.exceptions import FieldDoesNotExist
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_model(model_name, queryset_dict=None):
|
|||
|
|
if queryset_dict is None:
|
|||
|
|
model_infos = Model.objects.get(name=model_name)
|
|||
|
|
else:
|
|||
|
|
model_infos = Model.objects.filter(**queryset_dict)
|
|||
|
|
get_serializers = build_serializers(Model.__name__, Model, {}, False)
|
|||
|
|
model_data = get_serializers(model_infos).data
|
|||
|
|
app_config = apps.get_app_config(model_data["app"]["name"])
|
|||
|
|
return app_config.get_model(model_name)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_model_status(model_name, queryset_dict=None):
|
|||
|
|
if queryset_dict is None:
|
|||
|
|
model_infos = Model.objects.get(name=model_name)
|
|||
|
|
else:
|
|||
|
|
model_infos = Model.objects.filter(**queryset_dict)
|
|||
|
|
return model_infos
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_model_fields(model_name):
|
|||
|
|
model_id = Model.objects.get(name=model_name).id
|
|||
|
|
get_serializers = build_serializers(ModelField.__name__, ModelField, {}, False)
|
|||
|
|
return get_serializers(ModelField.objects.filter(model_id=model_id), many=True).data
|
|||
|
|
|
|||
|
|
|
|||
|
|
def reverse_add_sub_data(add_data, sub_model_instance=None):
|
|||
|
|
return_datas = []
|
|||
|
|
for items in add_data:
|
|||
|
|
need_del_key = []
|
|||
|
|
need_add_sub_list = {}
|
|||
|
|
for key, value in items.items():
|
|||
|
|
if isinstance(value, list) and len(value) > 0:
|
|||
|
|
sub_model = sub_model_instance._meta.get_field(key).remote_field.model
|
|||
|
|
res = reverse_add_sub_data(value, sub_model_instance=sub_model)
|
|||
|
|
need_add_sub_list.update({key: res})
|
|||
|
|
need_del_key.append(key)
|
|||
|
|
elif isinstance(value, list) and len(value) == 0:
|
|||
|
|
need_del_key.append(key)
|
|||
|
|
# 数据库添加数据
|
|||
|
|
for keys in need_del_key:
|
|||
|
|
del items[keys]
|
|||
|
|
items["uuid"] = str(uuid.uuid4())
|
|||
|
|
if 'id' in items:
|
|||
|
|
sub_item_ins = sub_model_instance.objects.get(id=items["id"])
|
|||
|
|
else:
|
|||
|
|
sub_item_ins = sub_model_instance.objects.create(**items)
|
|||
|
|
return_datas.append(sub_item_ins)
|
|||
|
|
for add_sub_item_k, add_sub_item_v in need_add_sub_list.items():
|
|||
|
|
for add_sub_item in add_sub_item_v:
|
|||
|
|
many_to_many_manager = getattr(sub_item_ins, add_sub_item_k)
|
|||
|
|
many_to_many_manager.add(add_sub_item)
|
|||
|
|
return return_datas
|
|||
|
|
|
|||
|
|
|
|||
|
|
def def_new_model(name, fields=None, app_label='', module='', options=None):
|
|||
|
|
class Meta:
|
|||
|
|
# Using type('Meta', ...) gives a dictproxy error during model creation
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
if app_label:
|
|||
|
|
# app_label必须用Meta内部类来设定
|
|||
|
|
setattr(Meta, 'app_label', app_label)
|
|||
|
|
|
|||
|
|
# 若提供了options参数,就要用更新Meta类
|
|||
|
|
if options is not None and not isinstance(options, bool):
|
|||
|
|
for key, value in options.iteritems():
|
|||
|
|
setattr(Meta, key, value)
|
|||
|
|
|
|||
|
|
# 创建一个字典来模拟类的声明,module和当前所在的module对应
|
|||
|
|
attrs = {'__module__': module, 'Meta': Meta}
|
|||
|
|
|
|||
|
|
# 创建这个类,这会触发ModelBase来处理
|
|||
|
|
model = type(name, (models.Model,), attrs)
|
|||
|
|
|
|||
|
|
# 加入所有提供的字段
|
|||
|
|
if fields:
|
|||
|
|
for item, value in fields.items():
|
|||
|
|
if isinstance(value, models.CharField):
|
|||
|
|
value.max_length = int(value.max_length)
|
|||
|
|
value.contribute_to_class(model, item)
|
|||
|
|
return model
|
|||
|
|
|
|||
|
|
|
|||
|
|
def create_model(name, fields=None, app_label='', module='', options=None):
|
|||
|
|
"""
|
|||
|
|
创建指定model
|
|||
|
|
"""
|
|||
|
|
# 查询当前app内的模型是否注册
|
|||
|
|
all_models = get_app_info(app_label)
|
|||
|
|
app_config = apps.get_app_config(app_label)
|
|||
|
|
for model in all_models:
|
|||
|
|
if model.__name__ == name:
|
|||
|
|
exist_list = get_models_field_detail(model)
|
|||
|
|
new_list = get_models_field_detail({}, fields=fields)
|
|||
|
|
add_item = []
|
|||
|
|
for item in model._meta.get_fields():
|
|||
|
|
if isinstance(item, ManyToManyRel):
|
|||
|
|
add_item = get_models_field_detail({}, fields={item.name: item})
|
|||
|
|
new_list.extend(add_item)
|
|||
|
|
for field in model._meta.get_fields():
|
|||
|
|
if isinstance(field, models.ManyToManyField):
|
|||
|
|
# 获取关联模型的序列化器
|
|||
|
|
related_model = field.remote_field.through
|
|||
|
|
if related_model.__name__ in app_config.models:
|
|||
|
|
del app_config.models[related_model.__name__]
|
|||
|
|
if judge_the_same(exist_list, new_list):
|
|||
|
|
## 清理模型缓存
|
|||
|
|
apps.clear_cache()
|
|||
|
|
|
|||
|
|
# 从 sys.modules 中移除旧模型
|
|||
|
|
model_key = f"{name.lower()}"
|
|||
|
|
|
|||
|
|
if model_key in app_config.models.keys():
|
|||
|
|
del app_config.models[model_key]
|
|||
|
|
|
|||
|
|
# 重新定义模型
|
|||
|
|
new_model = def_new_model(name, fields, app_label, module, options)
|
|||
|
|
judge_diff_be_two_models_and_change(model, new_model)
|
|||
|
|
return new_model
|
|||
|
|
else:
|
|||
|
|
return model
|
|||
|
|
model = def_new_model(name, fields, app_label, module, options)
|
|||
|
|
if not table_exists((app_label + "_" + name)):
|
|||
|
|
print("模型初始化:", app_label + "_" + name)
|
|||
|
|
install_model(model)
|
|||
|
|
return model
|
|||
|
|
|
|||
|
|
|
|||
|
|
class App(models.Model):
|
|||
|
|
name = models.CharField(max_length=255)
|
|||
|
|
name_cn = models.CharField(max_length=255)
|
|||
|
|
module = models.CharField(max_length=255)
|
|||
|
|
|
|||
|
|
def __str__(self):
|
|||
|
|
return self.name
|
|||
|
|
|
|||
|
|
|
|||
|
|
class Model(models.Model):
|
|||
|
|
app = models.ForeignKey(App, related_name='models', on_delete=models.CASCADE)
|
|||
|
|
name = models.CharField(max_length=255)
|
|||
|
|
name_cn = models.CharField(max_length=255)
|
|||
|
|
|
|||
|
|
def __str__(self):
|
|||
|
|
return self.name
|
|||
|
|
|
|||
|
|
def get_django_model(self):
|
|||
|
|
"Returns a functional Django model based on current data"
|
|||
|
|
# Get all associated fields into a list ready for dict()
|
|||
|
|
fields = [(f.name, f.get_django_field()) for f in self.model_fields.all()]
|
|||
|
|
# Use the create_model function defined above
|
|||
|
|
return create_model(self.name, dict(fields), self.app.name, self.app.module)
|
|||
|
|
|
|||
|
|
class Meta:
|
|||
|
|
unique_together = (('app', 'name'),)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ModelField(models.Model):
|
|||
|
|
model = models.ForeignKey(Model, related_name='model_fields', on_delete=models.CASCADE)
|
|||
|
|
name = models.CharField(max_length=255)
|
|||
|
|
name_cn = models.CharField(max_length=255)
|
|||
|
|
type = models.CharField(max_length=255)
|
|||
|
|
is_show = models.BooleanField(default=True)
|
|||
|
|
|
|||
|
|
def get_django_field(self):
|
|||
|
|
"Returns the correct field type, instantiated with applicable settings"
|
|||
|
|
# Get all associated settings into a list ready for dict()
|
|||
|
|
settings = [(s.name, s.value) for s in self.model_settings.all()]
|
|||
|
|
# Instantiate the field with the settings as **kwargs
|
|||
|
|
return getattr(models, self.type)(**dict(settings))
|
|||
|
|
|
|||
|
|
class Meta:
|
|||
|
|
unique_together = (('model', 'name'),)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ModelSetting(models.Model):
|
|||
|
|
field = models.ForeignKey(ModelField, related_name='model_settings', on_delete=models.CASCADE)
|
|||
|
|
name = models.CharField(max_length=255)
|
|||
|
|
name_cn = models.CharField(max_length=255)
|
|||
|
|
value = models.CharField(max_length=255)
|
|||
|
|
|
|||
|
|
class Meta:
|
|||
|
|
unique_together = (('field', 'name'),)
|