Python:如何使用存储在变量中的值来决定启动哪个类实例?

Python:如何使用存储在变量中的值来决定启动哪个类实例?,python,django,django-models,django-forms,metaprogramming,Python,Django,Django Models,Django Forms,Metaprogramming,我在建一个Django网站。我需要模拟许多不同的产品类别,如电视、笔记本电脑、女装、男鞋等 由于不同的产品类别具有不同的产品属性,因此每个类别都有其各自的型号:电视、笔记本电脑、女装、男鞋等 对于每个模型,我都创建了一个ModelForm。因此,我有TVForm、LaptopForm、女式服装form、男鞋form等 用户可以通过多级下拉框选择产品类别来输入产品详细信息。一旦用户选择了产品类别,我需要显示相应的产品表单 显而易见的方法是使用一个巨大的if-elif结构: # category i

我在建一个Django网站。我需要模拟许多不同的产品类别,如电视、笔记本电脑、女装、男鞋等

由于不同的产品类别具有不同的产品属性,因此每个类别都有其各自的型号:
电视、笔记本电脑、女装、男鞋等

对于每个模型,我都创建了一个ModelForm。因此,我有
TVForm、LaptopForm、女式服装form、男鞋form

用户可以通过多级下拉框选择产品类别来输入产品详细信息。一旦用户选择了产品类别,我需要显示相应的产品表单

显而易见的方法是使用一个巨大的
if-elif
结构:

# category is the product category selected by the user

if category == "TV":
    form = TVForm()
elif category == "Laptop":
    form = LaptopForm()
elif category == "WomensApparel":
    form = WomensApparelForm()
...
不幸的是,可能会有数百种,如果不是更多的类别。因此,上述方法很容易出错,也很乏味

是否有任何方法可以使用变量
category
的值直接选择和初始化适当的
ModelForm
,而无需求助于巨型
if elif
语句

比如:

# This doesn't work

model_form_name = category + "Form"
form = model_form_name()

有什么方法可以做到这一点吗?

如果您所有的
*表单
类都在一个模块中(我们称之为
表单
),您可以这样做:

import forms

form = getattr(forms, category + "Form")()

(显然,添加任何必要的验证,例如捕获
AttributeError
。从安全角度看,如果您使用的是命名模块而不是全局名称空间,那么对于某人来说,注入新的
*表单
类就有点困难。)

如果所有
*表单
类都在一个模块中(我们称之为
表单
),您可以执行以下操作:

import forms

form = getattr(forms, category + "Form")()

(显然,添加任何必要的验证,例如捕获
AttributeError
。从安全角度看,如果您使用的是命名模块而不是全局名称空间,那么要插入新的
*表单
类就有点难了。)一个简单的方法是维护一个类别名称字典以形成类

categories_and_classes = dict(TV = TVForm, Laptop = LaptopForm, ...)
然后,您可以使用该类别查找表单类:

form = categories_and_classes.get(category, DefaultForm)

或者,您可以使用约定,如@Zooba在中所述。如果表单的名称是统一的,那么这将起作用,比如说
+Form

一种简单的方法是维护一个类别名称字典以形成类

categories_and_classes = dict(TV = TVForm, Laptop = LaptopForm, ...)
然后,您可以使用该类别查找表单类:

form = categories_and_classes.get(category, DefaultForm)

或者,您也可以使用约定,如@Zooba在中所述。如果表单的名称是统一的,这将起作用,比如说
+Form

听起来您需要的是一个映射,或者Python中的字典。例如,创建一个将模型类别名称映射到模型类的字典。您可以使用另一个字典将它们映射到模型类。无论哪种方式,都可以将包含模型名的字符串映射到所需的任何对象

一种更“面向对象”的方法是只使用模型类字典,并向每个方法添加(可能是静态的)方法,这些方法返回或执行您需要执行的操作,例如返回适当的ModelForm。我的意思是:

class TV:
    @staticmethod
    def getform():
        return TVForm
...
class Laptop:
    @staticmethod
    def getform():
        return LaptopForm
...
class WomensApparel:
...etc...

Models = { 'TV':TV, 'Laptop':Laptop, 'WomensApparel':WomensApparel, ...etc }

form = Models[category].getform()

有了这两种技术,如果elif
结构,您就不需要编写那种巨大的
,而且如果您开始编写,这表明是时候重新考虑您的设计了。

听起来您需要的是一个映射,或者Python中的字典。例如,创建一个将模型类别名称映射到ModelForm类的字典。您可以另一种方法是将它们映射到模型类。无论哪种方法,您都可以将包含模型名称的字符串映射到您想要的任何对象

一种更“面向对象”的方法是只使用模型类字典,并向每个方法添加(可能是静态的)方法,这些方法返回或执行您需要执行的操作,例如返回适当的ModelForm。我的意思是:

class TV:
    @staticmethod
    def getform():
        return TVForm
...
class Laptop:
    @staticmethod
    def getform():
        return LaptopForm
...
class WomensApparel:
...etc...

Models = { 'TV':TV, 'Laptop':Laptop, 'WomensApparel':WomensApparel, ...etc }

form = Models[category].getform()

有了这两种技术,如果elif
结构,你就不需要编写那种巨大的
——如果你开始这样做,这是一个标志,是时候重新考虑你的设计了。

我同意Zooba的观点,你应该尽量避免全局的,但是如果出于某种原因,你所有的表单都是全局的,那么就使用
form=globals()[category+“form”]()
我同意Zooba的观点,如果可以的话,你应该避免使用全局形式,但是如果出于某种原因,你的所有表单都是全局的,那么使用
form=globals()[category+“form”](),
+1,这是唯一明智的方法,允许不同的表单名称或两个类别使用相同的表单,等等。这当然是最“正确的”方法。但是,由于我可以从
表单自动生成相同的字典。\uuuu dict\uuuuu
,这是不必要的重复工作(不要重复自己的原则).@您无法从
表单重新生成相同的dict.\uuu dict\uuuuuuuu
如果不同类别映射到同一表单。@AaronMcSmooth如果您在
表单
模块中包含
TVForm=LaptopForm
,您可以这样做。这实际上取决于您需要的查找动态程度(即从外部文件/数据库加载?).1,这是唯一合理的方法,允许不同的表单名称或两个类别使用相同的表单等。这当然是最“正确”的方法。但是,由于我可以从
表单自动生成相同的词典。这是不必要的重复工作(不要重复自己的原则).@您无法从
表单重新生成相同的dict.\uuu dict\uuuuuuuu
如果不同类别映射到同一表单。@AaronMcSmooth如果您在
表单
模块中包含
TVForm=LaptopForm
,您可以这样做。这实际上取决于您需要的查找动态程度(即从外部文件/数据库加载?)。我不喜欢静态方法要求模型知道在其上使用的是什么形式。一个简单的dict将类别映射到@Manoj Govindan使用的形式更简单。@AaronMcSmooth。这一点很好,但没有任何东西表明
getform()
必须