0

我目前正在开玩笑说如何使用 Django 建模。基本情况是我有一个对象应该作为 achassis并提供一些sockets. 然后有很多不同modules的东西放在socketsa上chassis。我想modules在 Django 中将这些不同的类建模为不同的类,但在数据库层使用一个公共类,可能涉及一些通用字段。

所以数据库模型可能看起来像这样:

class Module(models.model):
    name = models.CharField(max_length=128)
    # Or is there a better way to annotate a type?
    type = models.CharField(max_length=128) 
    string1 = models.CharField(max_length=128)
    string2 = models.CharField(max_length=128)
    ...
    int1 = models.IntegerField()

# Some kind of engine class that derives from Module
# but does nothing else then "mapping" the generic
# fields to something sensible

class Socket(models.Model):
    is_on = models.ForeignKey(Chassis)
    name = models.CharField(max_length=128)
    type = models.CharField(max_length=128)

class Connection(models.Model):
    chassis = models.ForeignKey(Chassis)
    module = models.ForeignKey(Module)
    via = models.ForeignKey(Socket)

class Chassis(models.Model):
    name = models.CharField(max_length=128)
    modules= models.ManyToManyField(Module, through='Connection')

class Group(models.Model):
    name = models.CharField(max_length=128)

当然,我不想用这种非规范化破坏我的逻辑。这就是为什么我暗示某种engine应该使用 Module 表的类,但提供“逻辑”getter 和 setter,有效地将“Horsepower”等数据映射到“int1”。

所以我的问题基本上是:

  • 我对 Django 所做的事情是否合理?还是有更好的(可能是内置的)方法来处理这个问题?
  • 是否可以根据Module.type字段自动构建正确的类型,即为非规范化模型提供包装器方法的类型?
4

2 回答 2

1

我对 Django 所做的事情是否合理?

一般的想法是好的,但非规范化可能会使您的查询不太理想。标准解决方案是Module为每种类型的模块进行子类化;这将创建一个module表以及每个模块类型的表,其中包含特定于类型的内容。当然,这假设您不会在运行时创建或删除模块类型。

也就是说,您的模型存在一些问题:

class Module(models.model):
    name = models.CharField(max_length=128)
    # Or is there a better way to annotate a type?
    type = models.CharField(max_length=128) 
    string1 = models.CharField(max_length=128)
    string2 = models.CharField(max_length=128)
    ...
    int1 = models.IntegerField()

通常,type会被标准化以节省空间:

class ModuleType(models.model):
    name = models.CharField(max_length=128)
    # Any other type-specific parameters.

class Module(models.model):
    name = models.CharField(max_length=128)
    type = models.ForeignKey(ModuleType, related_name="modules")
    string1 = models.CharField(max_length=128)
    string2 = models.CharField(max_length=128)
    ...
    int1 = models.IntegerField()

class Socket(models.Model):
    is_on = models.ForeignKey(Chassis)
    name = models.CharField(max_length=128)
    type = models.CharField(max_length=128)

class Connection(models.Model):
    chassis = models.ForeignKey(Chassis)
    module = models.ForeignKey(Module)
    via = models.ForeignKey(Socket)

class Chassis(models.Model):
    name = models.CharField(max_length=128)
    sockets = m
    modules= models.ManyToManyField(Model, through='Socket')

Chassis是一个烂摊子。您没有定义sockets,写Model在您可能想要的位置module,并且through可能应该参考Connection(模型必须在链接的两端through都有s)。ForeignKey但是从你的描述中,我得到了更简单的:

class Socket(models.Model):
    chassis = models.ForeignKey(Chassis, related_name="sockets")
    name = models.CharField(max_length=128)
    # Is `type` a ModuleType? If so, use a ForeignKey.
    # If not, create a SocketType model.
    type = models.___
    module = models.ForeignKey(Module, related_name="sockets")

class Chassis(models.Model):
    name = models.CharField(max_length=128)
    sockets = models.IntegerField()
    modules = models.ManyToManyField(Socket)

通过更好地描述您正在建模的内容,可以进一步细化。例如,我不确定 ManyToMany 是您想要的。您可能需要将机箱的设计(即给定类型机箱的所有实例共有的东西,包括其插槽)与该机箱的实例(将引用该设计,并有另一个表将插槽映射到模块) .


是否可以根据 Module.type 字段自动构造正确的类型?

这就是工厂设计模式。在 Python 中,您可以将其实现为构造函数字典:

class Module(models.model):
    # ...
    CONSTRUCTORS = {}

    @staticmethod
    def register_constructor(type_name, constructor):
        Module.CONSTRUCTORS[type_name] = constructor

    def construct(self):
        return Module.CONSTRUCTORS[self.type.name](self)

我认为您不需要特定的引擎类;各种模块类就足够了。

于 2012-09-19T13:13:58.170 回答
1

为了定义一个抽象基类,您可以执行以下操作:

class Module(models.model):
    name = models.CharField(max_length=128)
    type = models.CharField(max_length=128) 
    string1 = models.CharField(max_length=128)
    string2 = models.CharField(max_length=128)
    ...
    int1 = models.IntegerField()

    class Meta:
        abstract = True

class SpecificModule(Module):
     subClassField = models.CharField(max_length=128)

我建议阅读这部分文档,因为它是处理继承和抽象类的一个非常好的起点。

您还可以定义没有class Meta: abstract = True. 唯一的区别是abstract = True类的SpecificModule所有字段和抽象模块父类的所有字段都将在类SpecificModule的子类表中创建,而没有abstract = True定义的类Module的表将被创建,所有“模块表中可用的“通用”字段,以及表中类 SpecificModule 的所有子类特定字段。

编辑:回答关于父母和孩子之间关系的问题。

由于在子类表 ( docs )中创建了一个隐式的一对一字段,因此您可以使用此查询获取子对象。

#get the parent
parent = Module.objects.get(name="my first module")
#this is possible
print parent.name
>>> "my first module"
#this is not possible
print parent.subClassField
>>> Traceback (most recent call last):
    File "<console>", line 1, in <module>
    AttributeError: 'Module' object has no attribute 'subClassField'
#get the corresponding child
child = SpecificModule.objects.get(module_ptr_id=parent.pk)
#finally we can print the value
print child.subClassField

我认为Django还应该创建一个默认的related_name,但不确定它是哪个。

请注意,只有在这种情况下才会创建从父级到子级的隐式一对一关系abstract=False。但是,如果abstract = True您不会将抽象父级作为对象使用,因为它是抽象的..

于 2012-09-19T13:15:07.720 回答