如何使用装饰器或工厂从抽象类生成Django模型类?

时间:2015-02-26 12:04:27

标签: python django entity-attribute-value

对于一些项目,我们使用EAV的非常简单的变体。我们不需要过滤和查询数据集。我们查看了django-eaveav-django,它们不适合我们的项目,主要是因为我们不想使用GenericForeignKey。

我们现在看到的基本设置是这个(此问题不需要的字段可以专注于手头的问题):

# In the EAV app

class Attribute(models.Model):
    name = models.CharField(max-Length=100, unique=True)


class BaseValue(models.Model):
    value = models.TextField(null=False, blank=True)
    attribute = models.ForeignKey(Attribute)

    class Meta:
        abstract = True

在使用属性的应用中,我们可以这样做:

# Locations with attributes

class Location(models.Model):
    name = models.CharField(max_length=100, unique=True)


class LocationValue(BaseValue):
    object = models.ForeignKey(Location)

这很好地实现了目的,但如果我们能够生成LocationValue类,那就太好了。所以我们想做什么,但无法开始工作是这样的:

选项1,装饰者

# Locations with attributes

@has_attrs
class Location(models.Model):
    name = models.CharField(max-Length=100, unique=True)

# The `has_attrs` decorator should generate the LocationValue class

选项2,发电机/工厂

# Locations with attributes

class Location(models.Model):
    name = models.CharField(max-Length=100, unique=True)


LocationValue = value_class_for(Location)
# The function `value_class_for` should generate the LocationValue class

重要的是,LocationValue类是与Location相同的应用程序的一部分。这样做的原因是我们希望数据库模型即使对于那些直接查看它的人来说也是可以理解的(不是通过Django抽象层)。

此外,将有多个应用程序使用此功能,因此最终我们可能会有一个位置应用程序(Location,LocationValue),一个Monument应用程序(Monument,MonumentValue)等等。

我的问题:

  1. 是否可以将LocationValue类的生成委托给models.Model装饰器或工厂函数?
  2. 可用解决方案的优点/缺点是什么?
  3. 谢谢你分享你的知识!

1 个答案:

答案 0 :(得分:1)

实现此目的的pythonic方法是使用metaclass,这是在第一次创建类时调用的。因此,您可以控制类创建并创建其他类(将其视为某种类型的"工厂"用于类)。 Django也充分利用了这个"魔术"在设置模型类时。您可能希望查看创建Model类的Django's ModelBase metaclass(此外,您可能需要将其子类化以集成所需的功能)。