Python 是否可以创建一个Django模型,并将变量函数作为一个属性(通过_init__或某种方法传入)?

Python 是否可以创建一个Django模型,并将变量函数作为一个属性(通过_init__或某种方法传入)?,python,django,database,Python,Django,Database,我正在创建一个应用程序。这将产生数学问题。它们是一些可以改变参数的特定问题。每个问题都是不同的,需要不同的方法来解决(所有这些都将通过编程实现) 例如: 型号.py import random from django.db import models class Problem(models.Model): unformattedText = models.TextField() def __init__(self, unformattedText, genFunction,

我正在创建一个应用程序。这将产生数学问题。它们是一些可以改变参数的特定问题。每个问题都是不同的,需要不同的方法来解决(所有这些都将通过编程实现)

例如: 型号.py

import random
from django.db import models

class Problem(models.Model):
    unformattedText = models.TextField()

    def __init__(self, unformattedText, genFunction, *args, **kwargs):
        super(Problem, self).__init__(*args, **kwargs)
        self.unformatedText = unformattedText
        self.genFunction = genFunction

    def genQAPair():
        self.genFunction(self.unformattedText)
def genP1(text):
    num_1 = random.randrange(0, 100)
    num_2 = random.randrange(0, 100)
    text.format((num_1, num_2))
    return {'question':text, 'answer':num_1 - num_2}

def genP2(text, lim=4):
    num_1 = random.randrange(0, lim)
    text.format(num_1)
    return {'question':text, 'answer':num_1*40}


p1 = Problem(
        unformattedText='Sally has {} apples. Frank takes {}. How many apples does Sally have?',
        genFunction=genP1
)
p1.save()

p2 = Problem(
        unformattedText='John jumps {} feet into the air. How long does it take for him to age?',
        genFunction=genP2
)
p2.save()
class Problem(models.Model):
    unformattedText = models.TextField()
    genPath = models.TextField()
import importlib

def problem_view(request, problem_id):
    problem = Problem.objects.get(id=problem_id)
    gen_path, gen_name = problem.genPath.rsplit(".", 1)
    gen_module = importlib.import_module(gen_path)
    gen_function = getattr(gen_module, gen_name)

    context = gen_function(problem.unformattedText)
    return render(request, 'template.html', context)
视图.py

import random
from django.db import models

class Problem(models.Model):
    unformattedText = models.TextField()

    def __init__(self, unformattedText, genFunction, *args, **kwargs):
        super(Problem, self).__init__(*args, **kwargs)
        self.unformatedText = unformattedText
        self.genFunction = genFunction

    def genQAPair():
        self.genFunction(self.unformattedText)
def genP1(text):
    num_1 = random.randrange(0, 100)
    num_2 = random.randrange(0, 100)
    text.format((num_1, num_2))
    return {'question':text, 'answer':num_1 - num_2}

def genP2(text, lim=4):
    num_1 = random.randrange(0, lim)
    text.format(num_1)
    return {'question':text, 'answer':num_1*40}


p1 = Problem(
        unformattedText='Sally has {} apples. Frank takes {}. How many apples does Sally have?',
        genFunction=genP1
)
p1.save()

p2 = Problem(
        unformattedText='John jumps {} feet into the air. How long does it take for him to age?',
        genFunction=genP2
)
p2.save()
class Problem(models.Model):
    unformattedText = models.TextField()
    genPath = models.TextField()
import importlib

def problem_view(request, problem_id):
    problem = Problem.objects.get(id=problem_id)
    gen_path, gen_name = problem.genPath.rsplit(".", 1)
    gen_module = importlib.import_module(gen_path)
    gen_function = getattr(gen_module, gen_name)

    context = gen_function(problem.unformattedText)
    return render(request, 'template.html', context)
当我尝试此操作时,函数实际上并未保存。Django只保存整数
1
。当我启动模型的一个实例时,函数按预期存在,但显然只有
1
被保存到数据库中


额外问题:我实际上开始怀疑我是否需要Django模型来实现这一点。我使用Django是因为它非常容易将所有内容都放到网页上。有更好的方法吗?(可能将每个问题的文本存储在JSON文件中,并将生成函数存储在单独的脚本中。)

根据实际任务,有两个选项。我从最安全的选项到最危险(但灵活)的选项进行了排列:

1.存储函数标识符: 您可以将
genP1
genP2
存储为
'genP1'
'genP2'
——即按名称存储(也可以使用任何其他唯一标识符)

优点:

  • 您只能验证用户输入并执行受信任的代码,因为在这种情况下,您几乎可以控制所有内容
  • 您可以轻松调试函数,因为它们是系统的一部分
  • 缺点:

  • 您需要在代码中定义所有函数。这意味着如果您想添加新功能,您需要重新部署应用程序
  • 如果要存储函数名,则需要手动导入带有函数的模块(或包)并调用它们
  • 如果要存储标识符,则需要定义映射
    {identifier:path to actual function}
  • 2.使用DSL 您可以编写自己的DSL(或使用现有DSL)

    优点:

  • 您可以在运行时添加新函数,而无需重新部署应用程序
  • 您可以控制用户可以执行哪些代码
  • 您可以查看函数的源代码
  • 缺点:

  • 编写安全灵活的DSL是很困难的,特别是如果您想从中调用一些python代码
  • 调试大型函数很困难
  • 3.将它们序列化 可以使用

    优点:

  • 您可以在运行时添加新函数,而无需重新部署应用程序
  • 比编写自己的DSL更容易
  • 缺点:

  • 不安全-您不能执行不受信任的代码。如果您允许用户创建自己的函数,那么序列化就不是您的方式—而是定义(或使用现有的)安全DSL
  • 可能无法显示序列化函数的python源代码。有关更多信息:
  • 调试大型函数很困难
  • 4.只需存储实际的Python代码 只需将python源代码作为字符串存储在数据库中

    优点:

  • 您可以在运行时添加新函数,而无需重新部署应用程序
  • 您可以看到源代码,而无需任何附加处理
  • 比编写自己的DSL更容易
  • 缺点:

  • 不安全-您不能执行不受信任的代码。如果您允许用户创建自己的函数,那么存储源代码并不是您的方式——而是定义(或使用现有的)安全DSL
  • 调试大型函数很困难

  • Django应用程序的持久层是数据库,数据库模式由模型定义指定。在这种情况下,您只在模型中定义了一个字段,
    unformatedtext
    ;您尚未为相应的函数指定任何存储。您的
    self.genFunction=genFunction
    只是在内存中的对象上创建一个属性;它不会持久存在

    存储函数有多种可能的方法。您可以将其存储为原始文本;您可以将其存储为
    pickle
    blob;您可以存储函数路径和名称(例如,
    “my.path.to.problems.genP1”
    );或者做点别的。在任何情况下,都需要为该信息创建一个数据库字段

    下面是使用函数路径的示例解决方案的大致轮廓:

    型号.py

    import random
    from django.db import models
    
    class Problem(models.Model):
        unformattedText = models.TextField()
    
        def __init__(self, unformattedText, genFunction, *args, **kwargs):
            super(Problem, self).__init__(*args, **kwargs)
            self.unformatedText = unformattedText
            self.genFunction = genFunction
    
        def genQAPair():
            self.genFunction(self.unformattedText)
    
    def genP1(text):
        num_1 = random.randrange(0, 100)
        num_2 = random.randrange(0, 100)
        text.format((num_1, num_2))
        return {'question':text, 'answer':num_1 - num_2}
    
    def genP2(text, lim=4):
        num_1 = random.randrange(0, lim)
        text.format(num_1)
        return {'question':text, 'answer':num_1*40}
    
    
    p1 = Problem(
            unformattedText='Sally has {} apples. Frank takes {}. How many apples does Sally have?',
            genFunction=genP1
    )
    p1.save()
    
    p2 = Problem(
            unformattedText='John jumps {} feet into the air. How long does it take for him to age?',
            genFunction=genP2
    )
    p2.save()
    
    class Problem(models.Model):
        unformattedText = models.TextField()
        genPath = models.TextField()
    
    import importlib
    
    def problem_view(request, problem_id):
        problem = Problem.objects.get(id=problem_id)
        gen_path, gen_name = problem.genPath.rsplit(".", 1)
        gen_module = importlib.import_module(gen_path)
        gen_function = getattr(gen_module, gen_name)
    
        context = gen_function(problem.unformattedText)
        return render(request, 'template.html', context)
    
    视图.py

    import random
    from django.db import models
    
    class Problem(models.Model):
        unformattedText = models.TextField()
    
        def __init__(self, unformattedText, genFunction, *args, **kwargs):
            super(Problem, self).__init__(*args, **kwargs)
            self.unformatedText = unformattedText
            self.genFunction = genFunction
    
        def genQAPair():
            self.genFunction(self.unformattedText)
    
    def genP1(text):
        num_1 = random.randrange(0, 100)
        num_2 = random.randrange(0, 100)
        text.format((num_1, num_2))
        return {'question':text, 'answer':num_1 - num_2}
    
    def genP2(text, lim=4):
        num_1 = random.randrange(0, lim)
        text.format(num_1)
        return {'question':text, 'answer':num_1*40}
    
    
    p1 = Problem(
            unformattedText='Sally has {} apples. Frank takes {}. How many apples does Sally have?',
            genFunction=genP1
    )
    p1.save()
    
    p2 = Problem(
            unformattedText='John jumps {} feet into the air. How long does it take for him to age?',
            genFunction=genP2
    )
    p2.save()
    
    class Problem(models.Model):
        unformattedText = models.TextField()
        genPath = models.TextField()
    
    import importlib
    
    def problem_view(request, problem_id):
        problem = Problem.objects.get(id=problem_id)
        gen_path, gen_name = problem.genPath.rsplit(".", 1)
        gen_module = importlib.import_module(gen_path)
        gen_function = getattr(gen_module, gen_name)
    
        context = gen_function(problem.unformattedText)
        return render(request, 'template.html', context)
    
    只有您可以确定是否需要使用数据库。如果你只有几个固定的问题,那么你可以把所有的东西都塞进一个Python文件中,然后处理它。但是使用Django的模型有很多优点,包括使用admin的能力