首页 > 解决方案 > 如何从python中的给定文本创建一组类及其变量和方法

问题描述

我想从给定的文本配置中创建一组类,它的变量和方法,尤其是 django 模型,例如,我有一个模型列表要在 models.py 中创建

     classes=["users", "posts", "commnets"]
     vars= [{"a","b"},{"bb","vv"},{"aa"}]
     #methods=[{....},{....},{....}] not now

在models.py中,我想做这样的事情来创建那些类

for  i,j in zip(classes,vars):
    create_classes_from_string(i,j)

我如何编程#create_classes_from_string 以确保它使用该配置在我的数据库中创建表

标签: pythondjangoclass

解决方案


我可以从两个角度看待这个问题

  1. 动态创建python类的正常方法
  2. 专门创建动态 django 模型

但在这两种情况下,attrs 都应该定义为带有变量名及其值的 dict。因为在这里定义一个没有值的变量是没有意义的。

1.动态创建python类的常规方式

在这里,我们可以简单地使用type()方法来生成一个 python 类。稍后可以通过将它们添加到 locals() 内置函数来使用它们自己的名称创建对象。

下面提到一个例子

classes = ["Class1", "Class2"]

class_fileds = [
    {
        'cl1_var1': "test",
        'cl1_var2': 123,
    },
    {
        'cl2_var1': [1, 2, 3],
    }
]

classes_details = list(zip(classes, class_fileds))  # Python3 format

for class_details in classes_details:
    class_name = class_details[0]
    class_attrs = class_details[1]
    class_def = type(
            class_name,
            (object, ), # Base classes tuple
            class_attrs
        )
    locals().update({class_name: class_def})  # To associate the class with the script running

instance1 = Class1()
instance2 = Class2()

输出

>>> instance1 = Class1()
>>> instance2 = Class2()
>>>
>>> instance1.cl1_var1
'test'
>>> instance1.cl1_var2
123
>>> instance2.cl2_var1
[1, 2, 3]

这里列表中的类名,classes = ["Class1", "Class2"],可以像给定的那样使用,例如 Class1()、Class2() 等。这是通过将变量 Class1 和 Class2 添加到运行中来实现的使用 local()内置函数动态编写脚本

2.专门创建动态django模型

即使基本逻辑保持不变,也需要进行一些更改。

首先,我们需要了解 Django 中的动态模型创建。Django 为此提供了清晰的文档。

请参考,https://code.djangoproject.com/wiki/DynamicModels

一个例子可以看如下,你可以直接将下面的脚本添加到models.py文件中

from django.db import models
from django.db.models import CharField, IntegerField

# This is taken from https://code.djangoproject.com/wiki/DynamicModels#Ageneral-purposeapproach
def create_model(name, fields=None, app_label='', module='', options=None, admin_opts=None):
    class Meta:
        pass

    if app_label:
        setattr(Meta, 'app_label', app_label)

    if options is not None:
        for key, value in options.iteritems():
            setattr(Meta, key, value)
    attrs = {'__module__': module, 'Meta': Meta}  # Set up a dictionary to simulate declarations within a class

    if fields: # Add in any fields that were provided
        attrs.update(fields)
    model = type(name, (models.Model,), attrs)  # Create the class, which automatically triggers ModelBase processing

    return model


classes = ["Class1", "Class2"]

class_fileds = [
    {
        'cl1_var1': CharField(max_length=255),
        'cl1_var2': IntegerField(),
    },
    {
        'cl2_var2': IntegerField(),
    }
]

models_details = list(zip(classes, class_fileds))

for model_detail in models_details:
    model_name = model_detail[0]
    model_attrs = model_detail[1]

    model_def = create_model(
        model_name,
        fields=model_attrs,
        app_label=__package__,
        module= __name__,
    )

    locals()[model_name] = model_def

django shell 的输出

>>> from my_app.models import Class1
>>> Class1(cl1_var1="Able to create dynamic class", cl1_var2=12345).save()
>>> Class1.objects.all().values()
<QuerySet [{'cl1_var1': 'Able to create dynamic class', 'id': 3, 'cl1_var2': 12345}]>

此模型已添加到 django 应用程序my_app中,并且可以正常工作,并且需要注意一些事项

  1. 字段属性应小心处理,因为您将从文本文件中读取它
  2. 应使用 locals() 添加模型以从应用程序导入模型
  3. 方法,create_model 应取自参考链接,因为它支持更多功能,例如添加管理页面等
  4. 数据迁移也适用于这种模型

我的建议

上述方法可以毫无问题地工作,并且所有这些方法都受支持,但不要忘记一件事,动态导入的类和真正的导入存在性能差异。此外,这是一个有点复杂的结构,代码中的任何更改都应该非常小心地进行,以免破坏它。

所以我的建议是读取带有配置的文本文件,并使用一些魔法脚本(也可以在 python 中创建)从配置文件中生成 models.py 文件。因此,每次 text-config 文件发生更改时,您都必须生成 models.py 脚本。这样您还可以确保模型定义


推荐阅读