将模型名称作为字符串传递的最佳做法

时间:2013-09-16 14:05:59

标签: python django django-views django-context

我有两个不同的模型,我想在不同的时间通过公共字段名称进行类似的过滤,所以我编写了一个上下文函数,通过将字符串作为参数用作模型名称来处理两个模型。现在我正在使用eval(),但我的直觉中有些东西告诉我这是一个严重的错误。是否有更多的pythonic方式来做我正在描述的事情?

以下是我的代码目前的缩短版本:

def reference_context(model, value):
    menu = main_menu()
    info = company_info()
    pages = get_list_or_404(eval(model), category = value)

其次,有没有办法以类似的方式传递关键字,所以我可以有以下几点:

def reference_context(model, category, value):
    menu = main_menu()
    info = company_info()
    pages = get_list_or_404(eval(model), eval(category) = value)

欢迎并极力鼓励对任何其他问题的评论。

3 个答案:

答案 0 :(得分:1)

如果它们来自同一个模块(models.py),您可以使用getattr来检索模型类,并使用kwargs(带双星号的dict)这样:< / p>

from myapp import models

def reference_context(model, value):
    menu = main_menu()
    info = company_info()
    pages = get_list_or_404(getattr(models, model), **{category: value})

答案 1 :(得分:1)

您可以使用get_model实用程序功能,该功能获取应用名称和型号名称。

from django.db.models import get_model
User = get_model("auth", "User") # returns django.contrib.auth.models.User

答案 2 :(得分:1)

我真的不明白为什么你需要将模型作为字符串传递 - 只需传递模型参考。 E.g。

class ModelA(models.Model):
    ...

class ModelB(models.Model):
    ...

def reference_context(model, **kw):
    menu = main_menu()
    info = company_info()
    pages = get_list_or_404(model, **kw)
    # ...

在此设置中,您可以传递任何模型和任何所需的查询,例如

reference_context(ModelA, category="Hello")

reference_context(ModelB, item__ordered__lte=now)

正如我的评论中所解释的,如果您确实需要将字符串映射到模型,请使用显式注册表/映射。这可以防止人们操纵表单数据,这可能允许他们创建用户而不是例如“Book”:

model_map = dict(book=ModelA, magazine=ModelB)
reference_context(model_map[model_as_string], ...)